@wordpress/components
Version:
UI components for WordPress.
281 lines (275 loc) • 11.5 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _reactNative = require("react-native");
var _reactNativeFastImage = _interopRequireDefault(require("react-native-fast-image"));
var _i18n = require("@wordpress/i18n");
var _icons = require("@wordpress/icons");
var _compose = require("@wordpress/compose");
var _element = require("@wordpress/element");
var _utils = require("./utils");
var _style = _interopRequireDefault(require("./style.scss"));
var _iconRetry = _interopRequireDefault(require("./icon-retry"));
var _imageEditingButton = _interopRequireDefault(require("./image-editing-button"));
var _icon = _interopRequireDefault(require("../../icon"));
var _jsxRuntime = require("react/jsx-runtime");
/**
* External dependencies
*/
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
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] = (0, _element.useState)(null);
const [containerSize, setContainerSize] = (0, _element.useState)(null);
const [localURL, setLocalURL] = (0, _element.useState)(null);
const [networkURL, setNetworkURL] = (0, _element.useState)(null);
const [networkImageLoaded, setNetworkImageLoaded] = (0, _element.useState)(false);
// Disabled for Android due to https://github.com/WordPress/gutenberg/issues/43149
const Image = !shouldUseFastImage || _element.Platform.isAndroid ? _reactNative.Image : _reactNativeFastImage.default;
const imageResizeMode = !shouldUseFastImage || _element.Platform.isAndroid ? resizeMode : _reactNativeFastImage.default.resizeMode[resizeMode];
(0, _element.useEffect)(() => {
let isCurrent = true;
if (url) {
_reactNative.Image.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 (_element.Platform.isIOS) {
setNetworkURL(url);
} else if (_element.Platform.isAndroid) {
_reactNative.Image.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 || _iconRetry.default;
iconStyle = iconRetryStyles;
break;
case ICON_TYPE.OFFLINE:
icon = _icons.offline;
iconStyle = iconOfflineStyles;
break;
case ICON_TYPE.PLACEHOLDER:
icon = _icons.image;
iconStyle = iconPlaceholderStyles;
break;
case ICON_TYPE.UPLOAD:
icon = _icons.image;
iconStyle = iconUploadStyles;
break;
}
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_icon.default, {
icon: icon,
...iconStyle
});
};
const iconPlaceholderStyles = (0, _compose.usePreferredColorSchemeStyle)(_style.default.iconPlaceholder, _style.default.iconPlaceholderDark);
const iconUploadStyles = (0, _compose.usePreferredColorSchemeStyle)(_style.default.iconUpload, _style.default.iconUploadDark);
const iconOfflineStyles = (0, _compose.usePreferredColorSchemeStyle)(_style.default.iconOffline, _style.default.iconOfflineDark);
const retryIconStyles = (0, _compose.usePreferredColorSchemeStyle)(_style.default.retryIcon, _style.default.retryIconDark);
const iconRetryStyles = (0, _compose.usePreferredColorSchemeStyle)(_style.default.iconRetry, _style.default.iconRetryDark);
const retryContainerStyles = (0, _compose.usePreferredColorSchemeStyle)(_style.default.retryContainer, _style.default.retryContainerDark);
const uploadFailedTextStyles = (0, _compose.usePreferredColorSchemeStyle)(_style.default.uploadFailedText, _style.default.uploadFailedTextDark);
const placeholderStyles = [(0, _compose.usePreferredColorSchemeStyle)(_style.default.imageContainerUpload, _style.default.imageContainerUploadDark), focalPoint && _style.default.imageContainerUploadWithFocalpoint, imageHeight && {
height: imageHeight
}];
const customWidth = imageData?.width < containerSize?.width ? imageData?.width : _style.default.wide?.width;
const imageContainerStyles = [_style.default.imageContent, {
width: imageWidth === _style.default.wide?.width || imageData && imageWidth > 0 && imageWidth < containerSize?.width ? imageWidth : customWidth
}, resizeMode && {
width: _style.default.wide?.width
}, focalPoint && _style.default.focalPointContainer];
const imageStyles = [{
height: containerSize?.height
}, !resizeMode && {
aspectRatio: imageData?.aspectRatio
}, focalPoint && _style.default.focalPoint, focalPoint && (0, _utils.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 (_element.Platform.isIOS) {
calculatedSelectedHeight = containerSize && !isNaN(containerSize.height) ? containerSize.height + 1 : 0;
} else {
calculatedSelectedHeight = containerSize?.height;
}
const imageSelectedStyles = [(0, _compose.usePreferredColorSchemeStyle)(_style.default.imageBorder, _style.default.imageBorderDark), {
height: calculatedSelectedHeight
}];
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
style: [_style.default.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__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
accessible: true,
disabled: !isSelected,
accessibilityLabel: alt,
accessibilityHint: (0, _i18n.__)('Double tap to view larger.'),
accessibilityRole: "imagebutton",
style: imageContainerStyles,
children: [isSelected && highlightSelected && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: imageSelectedStyles
}), !imageData ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: placeholderStyles,
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: _style.default.imageUploadingIconContainer,
children: getIcon(ICON_TYPE.UPLOAD)
})
}) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
style: focalPoint && _style.default.focalPointContent,
children: [_element.Platform.isAndroid && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [networkImageLoaded && networkURL && /*#__PURE__*/(0, _jsxRuntime.jsx)(Image, {
style: imageStyles,
fadeDuration: 0,
source: {
uri: networkURL
},
...(!focalPoint && {
resizeMethod: 'scale'
}),
resizeMode: imageResizeMode,
testID: `network-image-${url}`
}), !networkImageLoaded && !networkURL && /*#__PURE__*/(0, _jsxRuntime.jsx)(Image, {
style: imageStyles,
fadeDuration: 0,
source: {
uri: localURL
},
...(!focalPoint && {
resizeMethod: 'scale'
}),
resizeMode: imageResizeMode
})]
}), _element.Platform.isIOS && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
children: [/*#__PURE__*/(0, _jsxRuntime.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__*/(0, _jsxRuntime.jsx)(Image, {
source: {
uri: networkURL
},
style: _style.default.nonVisibleImage,
onLoad: () => {
setNetworkImageLoaded(true);
}
})]
})]
}), (isUploadFailed || isUploadPaused) && retryMessage && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
style: [_style.default.imageContainer, retryContainerStyles],
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
style: [retryIconStyles, retryIcon && _style.default.customRetryIcon],
children: isUploadPaused ? getIcon(ICON_TYPE.OFFLINE) : getIcon(ICON_TYPE.RETRY)
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
style: uploadFailedTextStyles,
children: retryMessage
})]
})]
}, url), editButton && isSelected && !isUploadInProgress && /*#__PURE__*/(0, _jsxRuntime.jsx)(_imageEditingButton.default, {
onSelectMediaUploadOption: onSelectMediaUploadOption,
openMediaOptions: openMediaOptions,
url: !(isUploadFailed || isUploadPaused) && imageData && url,
pickerOptions: mediaPickerOptions
})]
});
};
var _default = exports.default = ImageComponent;
//# sourceMappingURL=index.native.js.map