Skip to content

Commit

Permalink
Merge pull request #42469 from dominictb/fix/40751
Browse files Browse the repository at this point in the history
fix: customize size behavior of image component
  • Loading branch information
madmax330 authored May 29, 2024
2 parents c244fa1 + aa836b7 commit db7fa86
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 25 deletions.
18 changes: 18 additions & 0 deletions src/components/Image/ImageBehaviorContextProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, {createContext} from 'react';

type ImageBehaviorContextValue = {
/**
* Determine whether or not to set the aspect ratio of the container div based on the image's aspect ratio.
*/
shouldSetAspectRatioInStyle: boolean;
};

const ImageBehaviorContext = createContext<ImageBehaviorContextValue>({
shouldSetAspectRatioInStyle: true,
});

function ImageBehaviorContextProvider({children, ...value}: {children: React.ReactNode} & ImageBehaviorContextValue) {
return <ImageBehaviorContext.Provider value={value}>{children}</ImageBehaviorContext.Provider>;
}

export {ImageBehaviorContext, ImageBehaviorContextProvider};
13 changes: 10 additions & 3 deletions src/components/Image/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React, {useCallback, useMemo, useState} from 'react';
import React, {useCallback, useContext, useMemo, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import BaseImage from './BaseImage';
import {ImageBehaviorContext} from './ImageBehaviorContextProvider';
import type {ImageOnLoadEvent, ImageOnyxProps, ImageOwnProps, ImageProps} from './types';

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

const {shouldSetAspectRatioInStyle} = useContext(ImageBehaviorContext);

const updateAspectRatio = useCallback(
(width: number, height: number) => {
if (!isObjectPositionTop) {
Expand All @@ -30,7 +33,6 @@ function Image({source: propsSource, isAuthTokenRequired = false, session, onLoa
const {width, height} = event.nativeEvent;

onLoad?.(event);

updateAspectRatio(width, height);
},
[onLoad, updateAspectRatio],
Expand Down Expand Up @@ -59,12 +61,17 @@ function Image({source: propsSource, isAuthTokenRequired = false, session, onLoa
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [propsSource, isAuthTokenRequired]);

/**
* If the image fails to load and the object position is top, we should hide the image by setting the opacity to 0.
*/
const shouldOpacityBeZero = isObjectPositionTop && !aspectRatio;

return (
<BaseImage
// eslint-disable-next-line react/jsx-props-no-spreading
{...forwardedProps}
onLoad={handleLoad}
style={[style, aspectRatio ? {aspectRatio, height: 'auto'} : {}, isObjectPositionTop && !aspectRatio && {opacity: 0}]}
style={[style, shouldSetAspectRatioInStyle && aspectRatio ? {aspectRatio, height: 'auto'} : {}, shouldOpacityBeZero && {opacity: 0}]}
source={source}
/>
);
Expand Down
47 changes: 25 additions & 22 deletions src/components/ReportActionItem/ReportActionItemImages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import React from 'react';
import {View} from 'react-native';
import {Polygon, Svg} from 'react-native-svg';
import {ImageBehaviorContextProvider} from '@components/Image/ImageBehaviorContextProvider';
import Text from '@components/Text';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
Expand Down Expand Up @@ -65,28 +66,30 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report
return (
<View style={styles.reportActionItemImagesContainer}>
<View style={[styles.reportActionItemImages, hoverStyle, heightStyle]}>
{shownImages.map(({thumbnail, isThumbnail, image, transaction, isLocalFile, fileExtension, filename}, index) => {
// Show a border to separate multiple images. Shown to the right for each except the last.
const shouldShowBorder = shownImages.length > 1 && index < shownImages.length - 1;
const borderStyle = shouldShowBorder ? styles.reportActionItemImageBorder : {};
return (
<View
key={`${index}-${image}`}
style={[styles.reportActionItemImage, borderStyle, hoverStyle]}
>
<ReportActionItemImage
thumbnail={thumbnail}
fileExtension={fileExtension}
image={image}
isLocalFile={isLocalFile}
filename={filename}
transaction={transaction}
isThumbnail={isThumbnail}
isSingleImage={numberOfShownImages === 1}
/>
</View>
);
})}
<ImageBehaviorContextProvider shouldSetAspectRatioInStyle={false}>
{shownImages.map(({thumbnail, isThumbnail, image, transaction, isLocalFile, fileExtension, filename}, index) => {
// Show a border to separate multiple images. Shown to the right for each except the last.
const shouldShowBorder = shownImages.length > 1 && index < shownImages.length - 1;
const borderStyle = shouldShowBorder ? styles.reportActionItemImageBorder : {};
return (
<View
key={`${index}-${image}`}
style={[styles.reportActionItemImage, borderStyle, hoverStyle]}
>
<ReportActionItemImage
thumbnail={thumbnail}
fileExtension={fileExtension}
image={image}
isLocalFile={isLocalFile}
filename={filename}
transaction={transaction}
isThumbnail={isThumbnail}
isSingleImage={numberOfShownImages === 1}
/>
</View>
);
})}
</ImageBehaviorContextProvider>
</View>
{remaining > 0 && (
<View style={[styles.reportActionItemImagesMoreContainer]}>
Expand Down

0 comments on commit db7fa86

Please sign in to comment.