Skip to content

Commit

Permalink
fix: peer dependency issue
Browse files Browse the repository at this point in the history
  • Loading branch information
ridvanaltun committed Jun 6, 2022
1 parent 74bf57c commit 81f755b
Show file tree
Hide file tree
Showing 12 changed files with 48,205 additions and 8,939 deletions.
38,645 changes: 38,645 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
},
"dependencies": {
"prop-types": "^15.8.1",
"react-native-auto-height-image": "^3.2.4",
"react-native-modalbox": "^2.0.2",
"react-native-status-bar-height": "^2.6.0",
"react-native-swipe-gestures": "^1.0.5"
Expand Down
23 changes: 23 additions & 0 deletions src/components/AutoHeightImage/AnimatableImage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Animated, Image, ImageBackground } from 'react-native';

function AnimatableImage(props) {
const { animated, children, ...rest } = props;

const ImageComponent = children
? ImageBackground
: animated
? Animated.Image
: Image;

return <ImageComponent {...rest}>{children}</ImageComponent>;
}

AnimatableImage.propTypes = Image.propTypes | Animated.Image.propTypes;

AnimatableImage.defaultProps = {
animated: false,
};

export default AnimatableImage;
84 changes: 84 additions & 0 deletions src/components/AutoHeightImage/AutoHeightImage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* @since 2017-04-11 19:10:08
* @author vivaxy
*/
import React, { useEffect, useState, useRef } from 'react';
import ImagePolyfill from './ImagePolyfill';
import AnimatableImage from './AnimatableImage';
import PropTypes from 'prop-types';

import { getImageSizeFitWidth, getImageSizeFitWidthFromCache } from './cache';
import { NOOP, DEFAULT_HEIGHT } from './helpers';

// remove `resizeMode` props from `Image.propTypes`
const { resizeMode, ...ImagePropTypes } = AnimatableImage.propTypes;

function AutoHeightImage(props) {
const { onHeightChange, source, width, style, maxHeight, onError, ...rest } =
props;
const [height, setHeight] = useState(
getImageSizeFitWidthFromCache(source, width, maxHeight).height ||
DEFAULT_HEIGHT
);
const mountedRef = useRef(false);

useEffect(function () {
mountedRef.current = true;
return function () {
mountedRef.current = false;
};
}, []);

useEffect(
function () {
(async function () {
try {
const { height: newHeight } = await getImageSizeFitWidth(
source,
width,
maxHeight
);
if (mountedRef.current) {
// might trigger `onHeightChange` with same `height` value
// dedupe maybe?
setHeight(newHeight);
onHeightChange(newHeight);
}
} catch (e) {
onError(e);
}
})();
},
[source, onHeightChange, width, maxHeight]
);

// StyleSheet.create will cache styles, not what we want
const imageStyles = { width, height };

// Since it only makes sense to use polyfill with remote images
const ImageComponent = source.uri ? ImagePolyfill : AnimatableImage;
return (
<ImageComponent
source={source}
style={[imageStyles, style]}
onError={onError}
{...rest}
/>
);
}

AutoHeightImage.propTypes = {
...ImagePropTypes,
width: PropTypes.number.isRequired,
maxHeight: PropTypes.number,
onHeightChange: PropTypes.func,
animated: PropTypes.bool,
};

AutoHeightImage.defaultProps = {
maxHeight: Infinity,
onHeightChange: NOOP,
animated: false,
};

export default AutoHeightImage;
30 changes: 30 additions & 0 deletions src/components/AutoHeightImage/ErrorableImage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { useState } from 'react';

import AutoHeightImage from './AutoHeightImage';

function ErrorableImage(props) {
const { source, fallbackSource, onError, ...rest } = props;

const [error, setError] = useState(false);

const shouldUseFallbackSource = error && fallbackSource;

return (
<AutoHeightImage
source={shouldUseFallbackSource ? fallbackSource : source}
onError={(_e) => {
// if an error hasn't already been seen, try to load the error image
// instead
if (!error) {
setError(true);
}

// also propagate to error handler if it is specified
onError && onError(_e);
}}
{...rest}
/>
);
}

export default ErrorableImage;
33 changes: 33 additions & 0 deletions src/components/AutoHeightImage/ImagePolyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useEffect } from 'react';
import { Platform, Image } from 'react-native';
import AnimatableImage from './AnimatableImage';

const isAndroid = () => Platform.OS === 'android';

/**
* An extension of the Image class which fixes an Android bug where remote images wouldn't fire the
* Image#onError() callback when the image failed to load due to a 404 response.
*
* This component should only be used for loading remote images, not local resources.
*/
function ImagePolyfill(props) {
const { source, onError, ...rest } = props;

const verifyImage = () => {
const { uri } = source;
Image.prefetch(uri).catch((e) => onError(e));
};

useEffect(() => {
if (source && source.uri && onError && isAndroid()) {
verifyImage();
}
}, [source, onError]);

return <AnimatableImage source={source} {...rest} />;
}

ImagePolyfill.propTypes = AnimatableImage.propTypes;
ImagePolyfill.defaultProps = AnimatableImage.defaultProps;

export default ImagePolyfill;
83 changes: 83 additions & 0 deletions src/components/AutoHeightImage/cache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* @since 2017-04-24 20:50:41
* @author vivaxy
*/

import { Image } from 'react-native';
// undocumented but part of react-native; see
// https://github.com/facebook/react-native/issues/5603#issuecomment-297959695
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';

/**
* store with
* key: image
* value: {
* width: 100,
* height: 100,
* }
*/
const cache = new Map();

const getImageSizeFromCache = (image) => {
if (typeof image === 'number') {
return cache.get(image);
} else {
return cache.get(image.uri);
}
};

const loadImageSize = (image) => {
return new Promise((resolve, reject) => {
//number indicates import X or require(X) was used (i.e. local file)
if (typeof image === 'number') {
const { width, height } = resolveAssetSource(image);
resolve({ width, height });
} else {
Image.getSize(
image.uri,
(width, height) => {
// success
resolve({ width, height });
},
reject
);
}
});
};

export const getImageSizeFitWidthFromCache = (image, toWidth, maxHeight) => {
const size = getImageSizeFromCache(image);
if (size) {
const { width, height } = size;
if (!width || !height) return { width: 0, height: 0 };
const scaledHeight = (toWidth * height) / width;
return {
width: toWidth,
height: scaledHeight > maxHeight ? maxHeight : scaledHeight,
};
}
return {};
};

const getImageSizeMaybeFromCache = async (image) => {
let size = getImageSizeFromCache(image);
if (!size) {
size = await loadImageSize(image);
if (typeof image === 'number') {
cache.set(image, size);
} else {
cache.set(image.uri, size);
}
}
return size;
};

export const getImageSizeFitWidth = async (image, toWidth, maxHeight) => {
const { width, height } = await getImageSizeMaybeFromCache(image);
if (!width || !height) return { width: 0, height: 0 };
const scaledHeight = (toWidth * height) / width;
return {
width: toWidth,
height: scaledHeight > maxHeight ? maxHeight : scaledHeight,
};
};
2 changes: 2 additions & 0 deletions src/components/AutoHeightImage/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const NOOP = () => {};
export const DEFAULT_HEIGHT = 0;
22 changes: 22 additions & 0 deletions src/components/AutoHeightImage/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as React from 'react';
import { ImageProps } from 'react-native';

interface TSource {
uri: string;
}

export interface AutoHeightImageProps extends ImageProps {
source: number | TSource;
width: number;
maxHeight?: number;
fallbackSource?: number | TSource;
onHeightChange?: (height: number) => void;
animated?: boolean;
}

declare class AutoHeightImage extends React.Component<
AutoHeightImageProps,
any
> {}

export default AutoHeightImage;
3 changes: 3 additions & 0 deletions src/components/AutoHeightImage/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ErrorableImage from './ErrorableImage';

export default ErrorableImage;
2 changes: 1 addition & 1 deletion src/components/StoryListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
SafeAreaView,
} from 'react-native';
import GestureRecognizer from 'react-native-swipe-gestures';
import AutoHeightImage from 'react-native-auto-height-image';
import AutoHeightImage from './AutoHeightImage';

import { usePrevious } from '../helpers/StateHelpers';
import { isNullOrWhitespace } from '../helpers/ValidationHelpers';
Expand Down
Loading

0 comments on commit 81f755b

Please sign in to comment.