@wordpress/components
Version:
UI components for WordPress.
273 lines (269 loc) • 10.2 kB
JavaScript
/**
* External dependencies
*/
import { Image as RNImage, Text, View } from 'react-native';
import FastImage from 'react-native-fast-image';
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { image, offline } from '@wordpress/icons';
import { usePreferredColorSchemeStyle } from '@wordpress/compose';
import { useEffect, useState, Platform } from '@wordpress/element';
/**
* Internal dependencies
*/
import { getImageWithFocalPointStyles } from './utils';
import styles from './style.scss';
import SvgIconRetry from './icon-retry';
import ImageEditingButton from './image-editing-button';
import Icon from '../../icon';
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
const ICON_TYPE = {
OFFLINE: 'offline',
PLACEHOLDER: 'placeholder',
RETRY: 'retry',
UPLOAD: 'upload'
};
const ImageComponent = ({
align,
alt,
editButton = true,
focalPoint,
height: imageHeight,
highlightSelected = true,
isSelected,
shouldUseFastImage,
isUploadFailed,
isUploadPaused,
isUploadInProgress,
mediaPickerOptions,
onImageDataLoad,
onSelectMediaUploadOption,
openMediaOptions,
resizeMode,
retryMessage,
retryIcon,
url,
shapeStyle,
style,
width: imageWidth
}) => {
const [imageData, setImageData] = useState(null);
const [containerSize, setContainerSize] = useState(null);
const [localURL, setLocalURL] = useState(null);
const [networkURL, setNetworkURL] = useState(null);
const [networkImageLoaded, setNetworkImageLoaded] = useState(false);
// Disabled for Android due to https://github.com/WordPress/gutenberg/issues/43149
const Image = !shouldUseFastImage || Platform.isAndroid ? RNImage : FastImage;
const imageResizeMode = !shouldUseFastImage || Platform.isAndroid ? resizeMode : FastImage.resizeMode[resizeMode];
useEffect(() => {
let isCurrent = true;
if (url) {
RNImage.getSize(url, (imgWidth, imgHeight) => {
if (!isCurrent) {
return;
}
const metaData = {
aspectRatio: imgWidth / imgHeight,
width: imgWidth,
height: imgHeight
};
setImageData(metaData);
if (onImageDataLoad) {
onImageDataLoad(metaData);
}
});
if (url.startsWith('file:///')) {
setLocalURL(url);
setNetworkURL(null);
setNetworkImageLoaded(false);
} else if (url.startsWith('https://')) {
if (Platform.isIOS) {
setNetworkURL(url);
} else if (Platform.isAndroid) {
RNImage.prefetch(url).then(() => {
if (!isCurrent) {
return;
}
setNetworkURL(url);
setNetworkImageLoaded(true);
}, () => {
// This callback is called when the image fails to load,
// but these events are handled by `isUploadFailed`
// and `isUploadPaused` events instead.
//
// Ignoring the error event will persist the local image URI.
});
}
}
}
return () => isCurrent = false;
// See https://github.com/WordPress/gutenberg/pull/41166
}, [url]);
const onContainerLayout = event => {
const {
height,
width
} = event.nativeEvent.layout;
if (width !== 0 && height !== 0 && (containerSize?.width !== width || containerSize?.height !== height)) {
setContainerSize({
width,
height
});
}
};
const getIcon = iconType => {
let icon;
let iconStyle;
switch (iconType) {
case ICON_TYPE.RETRY:
icon = retryIcon || SvgIconRetry;
iconStyle = iconRetryStyles;
break;
case ICON_TYPE.OFFLINE:
icon = offline;
iconStyle = iconOfflineStyles;
break;
case ICON_TYPE.PLACEHOLDER:
icon = image;
iconStyle = iconPlaceholderStyles;
break;
case ICON_TYPE.UPLOAD:
icon = image;
iconStyle = iconUploadStyles;
break;
}
return /*#__PURE__*/_jsx(Icon, {
icon: icon,
...iconStyle
});
};
const iconPlaceholderStyles = usePreferredColorSchemeStyle(styles.iconPlaceholder, styles.iconPlaceholderDark);
const iconUploadStyles = usePreferredColorSchemeStyle(styles.iconUpload, styles.iconUploadDark);
const iconOfflineStyles = usePreferredColorSchemeStyle(styles.iconOffline, styles.iconOfflineDark);
const retryIconStyles = usePreferredColorSchemeStyle(styles.retryIcon, styles.retryIconDark);
const iconRetryStyles = usePreferredColorSchemeStyle(styles.iconRetry, styles.iconRetryDark);
const retryContainerStyles = usePreferredColorSchemeStyle(styles.retryContainer, styles.retryContainerDark);
const uploadFailedTextStyles = usePreferredColorSchemeStyle(styles.uploadFailedText, styles.uploadFailedTextDark);
const placeholderStyles = [usePreferredColorSchemeStyle(styles.imageContainerUpload, styles.imageContainerUploadDark), focalPoint && styles.imageContainerUploadWithFocalpoint, imageHeight && {
height: imageHeight
}];
const customWidth = imageData?.width < containerSize?.width ? imageData?.width : styles.wide?.width;
const imageContainerStyles = [styles.imageContent, {
width: imageWidth === styles.wide?.width || imageData && imageWidth > 0 && imageWidth < containerSize?.width ? imageWidth : customWidth
}, resizeMode && {
width: styles.wide?.width
}, focalPoint && styles.focalPointContainer];
const imageStyles = [{
height: containerSize?.height
}, !resizeMode && {
aspectRatio: imageData?.aspectRatio
}, focalPoint && styles.focalPoint, focalPoint && getImageWithFocalPointStyles(focalPoint, containerSize, imageData), !focalPoint && imageData && containerSize && {
height: imageData?.width > containerSize?.width && !imageWidth ? containerSize?.width / imageData?.aspectRatio : undefined
}, imageHeight && {
height: imageHeight
}, shapeStyle];
// On iOS, add 1 to height to account for the 1px non-visible image
// that is used to determine when the network image has loaded
// We also must verify that it is not NaN, as it can be NaN when the image is loading.
// This is not necessary on Android as the non-visible image is not used.
let calculatedSelectedHeight;
if (Platform.isIOS) {
calculatedSelectedHeight = containerSize && !isNaN(containerSize.height) ? containerSize.height + 1 : 0;
} else {
calculatedSelectedHeight = containerSize?.height;
}
const imageSelectedStyles = [usePreferredColorSchemeStyle(styles.imageBorder, styles.imageBorderDark), {
height: calculatedSelectedHeight
}];
return /*#__PURE__*/_jsxs(View, {
style: [styles.container,
// Only set alignItems if an image exists because alignItems causes the placeholder
// to disappear when an aligned image can't be downloaded
// https://github.com/wordpress-mobile/gutenberg-mobile/issues/1592
imageData && align && {
alignItems: align
}, style],
onLayout: onContainerLayout,
children: [/*#__PURE__*/_jsxs(View, {
accessible: true,
disabled: !isSelected,
accessibilityLabel: alt,
accessibilityHint: __('Double tap to view larger.'),
accessibilityRole: "imagebutton",
style: imageContainerStyles,
children: [isSelected && highlightSelected && /*#__PURE__*/_jsx(View, {
style: imageSelectedStyles
}), !imageData ? /*#__PURE__*/_jsx(View, {
style: placeholderStyles,
children: /*#__PURE__*/_jsx(View, {
style: styles.imageUploadingIconContainer,
children: getIcon(ICON_TYPE.UPLOAD)
})
}) : /*#__PURE__*/_jsxs(View, {
style: focalPoint && styles.focalPointContent,
children: [Platform.isAndroid && /*#__PURE__*/_jsxs(_Fragment, {
children: [networkImageLoaded && networkURL && /*#__PURE__*/_jsx(Image, {
style: imageStyles,
fadeDuration: 0,
source: {
uri: networkURL
},
...(!focalPoint && {
resizeMethod: 'scale'
}),
resizeMode: imageResizeMode,
testID: `network-image-${url}`
}), !networkImageLoaded && !networkURL && /*#__PURE__*/_jsx(Image, {
style: imageStyles,
fadeDuration: 0,
source: {
uri: localURL
},
...(!focalPoint && {
resizeMethod: 'scale'
}),
resizeMode: imageResizeMode
})]
}), Platform.isIOS && /*#__PURE__*/_jsxs(_Fragment, {
children: [/*#__PURE__*/_jsx(Image, {
style: imageStyles,
source: {
uri: networkURL && networkImageLoaded ? networkURL : localURL || url
},
...(!focalPoint && {
resizeMethod: 'scale'
}),
resizeMode: imageResizeMode,
testID: `network-image-${networkURL && networkImageLoaded ? networkURL : localURL || url}`
}), /*#__PURE__*/_jsx(Image, {
source: {
uri: networkURL
},
style: styles.nonVisibleImage,
onLoad: () => {
setNetworkImageLoaded(true);
}
})]
})]
}), (isUploadFailed || isUploadPaused) && retryMessage && /*#__PURE__*/_jsxs(View, {
style: [styles.imageContainer, retryContainerStyles],
children: [/*#__PURE__*/_jsx(View, {
style: [retryIconStyles, retryIcon && styles.customRetryIcon],
children: isUploadPaused ? getIcon(ICON_TYPE.OFFLINE) : getIcon(ICON_TYPE.RETRY)
}), /*#__PURE__*/_jsx(Text, {
style: uploadFailedTextStyles,
children: retryMessage
})]
})]
}, url), editButton && isSelected && !isUploadInProgress && /*#__PURE__*/_jsx(ImageEditingButton, {
onSelectMediaUploadOption: onSelectMediaUploadOption,
openMediaOptions: openMediaOptions,
url: !(isUploadFailed || isUploadPaused) && imageData && url,
pickerOptions: mediaPickerOptions
})]
});
};
export default ImageComponent;
//# sourceMappingURL=index.native.js.map