"use strict"; exports.__esModule = true; exports.default = void 0; var _applyNativeMethods = _interopRequireDefault(require("../../modules/applyNativeMethods")); var _createElement = _interopRequireDefault(require("../createElement")); var _css = _interopRequireDefault(require("../StyleSheet/css")); var _AssetRegistry = require("../../modules/AssetRegistry"); var _resolveShadowValue = _interopRequireDefault(require("../StyleSheet/resolveShadowValue")); var _ImageLoader = _interopRequireDefault(require("../../modules/ImageLoader")); var _ImageResizeMode = _interopRequireDefault(require("./ImageResizeMode")); var _ImageSourcePropType = _interopRequireDefault(require("./ImageSourcePropType")); var _ImageStylePropTypes = _interopRequireDefault(require("./ImageStylePropTypes")); var _ImageUriCache = _interopRequireDefault(require("./ImageUriCache")); var _StyleSheet = _interopRequireDefault(require("../StyleSheet")); var _StyleSheetPropType = _interopRequireDefault(require("../../modules/StyleSheetPropType")); var _View = _interopRequireDefault(require("../View")); var _ViewPropTypes = _interopRequireDefault(require("../ViewPropTypes")); var _propTypes = require("prop-types"); var _react = _interopRequireWildcard(require("react")); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } var emptyObject = {}; var STATUS_ERRORED = 'ERRORED'; var STATUS_LOADED = 'LOADED'; var STATUS_LOADING = 'LOADING'; var STATUS_PENDING = 'PENDING'; var STATUS_IDLE = 'IDLE'; var getImageState = function getImageState(uri, shouldDisplaySource) { return shouldDisplaySource ? STATUS_LOADED : uri ? STATUS_PENDING : STATUS_IDLE; }; var resolveAssetDimensions = function resolveAssetDimensions(source) { if (typeof source === 'number') { var _getAssetByID = (0, _AssetRegistry.getAssetByID)(source), height = _getAssetByID.height, width = _getAssetByID.width; return { height: height, width: width }; } else if (typeof source === 'object') { var _height = source.height, _width = source.width; return { height: _height, width: _width }; } }; var svgDataUriPattern = /^(data:image\/svg\+xml;utf8,)(.*)/; var resolveAssetUri = function resolveAssetUri(source) { var uri = ''; if (typeof source === 'number') { // get the URI from the packager var asset = (0, _AssetRegistry.getAssetByID)(source); var scale = asset.scales[0]; var scaleSuffix = scale !== 1 ? "@" + scale + "x" : ''; uri = asset ? asset.httpServerLocation + "/" + asset.name + scaleSuffix + "." + asset.type : ''; } else if (typeof source === 'string') { uri = source; } else if (source && typeof source.uri === 'string') { uri = source.uri; } if (uri) { var match = uri.match(svgDataUriPattern); // inline SVG markup may contain characters (e.g., #, ") that need to be escaped if (match) { var prefix = match[1], svg = match[2]; var encodedSvg = encodeURIComponent(svg); return "" + prefix + encodedSvg; } } return uri; }; var filterId = 0; var createTintColorSVG = function createTintColorSVG(tintColor, id) { return tintColor && id != null ? _react.default.createElement("svg", { style: { position: 'absolute', height: 0, visibility: 'hidden', width: 0 } }, _react.default.createElement("defs", null, _react.default.createElement("filter", { id: "tint-" + id }, _react.default.createElement("feFlood", { floodColor: "" + tintColor }), _react.default.createElement("feComposite", { in2: "SourceAlpha", operator: "atop" })))) : null; }; var Image = /*#__PURE__*/ function (_Component) { _inheritsLoose(Image, _Component); Image.getSize = function getSize(uri, success, failure) { _ImageLoader.default.getSize(uri, success, failure); }; Image.prefetch = function prefetch(uri) { return _ImageLoader.default.prefetch(uri).then(function () { // Add the uri to the cache so it can be immediately displayed when used // but also immediately remove it to correctly reflect that it has no active references _ImageUriCache.default.add(uri); _ImageUriCache.default.remove(uri); }); }; Image.queryCache = function queryCache(uris) { var result = {}; uris.forEach(function (u) { if (_ImageUriCache.default.has(u)) { result[u] = 'disk/memory'; } }); return Promise.resolve(result); }; function Image(props, context) { var _this; _this = _Component.call(this, props, context) || this; // If an image has been loaded before, render it immediately _this._filterId = 0; _this._imageRef = null; _this._imageRequestId = null; _this._imageState = null; _this._isMounted = false; _this._createLayoutHandler = function (resizeMode) { var onLayout = _this.props.onLayout; if (resizeMode === 'center' || resizeMode === 'repeat' || onLayout) { return function (e) { var layout = e.nativeEvent.layout; onLayout && onLayout(e); _this.setState(function () { return { layout: layout }; }); }; } }; _this._getBackgroundSize = function (resizeMode) { if (_this._imageRef && (resizeMode === 'center' || resizeMode === 'repeat')) { var _this$_imageRef = _this._imageRef, naturalHeight = _this$_imageRef.naturalHeight, naturalWidth = _this$_imageRef.naturalWidth; var _this$state$layout = _this.state.layout, height = _this$state$layout.height, width = _this$state$layout.width; if (naturalHeight && naturalWidth && height && width) { var scaleFactor = Math.min(1, width / naturalWidth, height / naturalHeight); var x = Math.ceil(scaleFactor * naturalWidth); var y = Math.ceil(scaleFactor * naturalHeight); return { backgroundSize: x + "px " + y + "px" }; } } }; _this._onError = function () { var _this$props = _this.props, onError = _this$props.onError, source = _this$props.source; _this._updateImageState(STATUS_ERRORED); if (onError) { onError({ nativeEvent: { error: "Failed to load resource " + resolveAssetUri(source) + " (404)" } }); } _this._onLoadEnd(); }; _this._onLoad = function (e) { var _this$props2 = _this.props, onLoad = _this$props2.onLoad, source = _this$props2.source; var event = { nativeEvent: e }; _ImageUriCache.default.add(resolveAssetUri(source)); _this._updateImageState(STATUS_LOADED); if (onLoad) { onLoad(event); } _this._onLoadEnd(); }; _this._setImageRef = function (ref) { _this._imageRef = ref; }; var uri = resolveAssetUri(props.source); var shouldDisplaySource = _ImageUriCache.default.has(uri); _this.state = { layout: {}, shouldDisplaySource: shouldDisplaySource }; _this._imageState = getImageState(uri, shouldDisplaySource); _this._filterId = filterId; filterId++; return _this; } var _proto = Image.prototype; _proto.componentDidMount = function componentDidMount() { this._isMounted = true; if (this._imageState === STATUS_PENDING) { this._createImageLoader(); } else if (this._imageState === STATUS_LOADED) { this._onLoad({ target: this._imageRef }); } }; _proto.componentDidUpdate = function componentDidUpdate(prevProps) { var prevUri = resolveAssetUri(prevProps.source); var uri = resolveAssetUri(this.props.source); var hasDefaultSource = this.props.defaultSource != null; if (prevUri !== uri) { _ImageUriCache.default.remove(prevUri); var isPreviouslyLoaded = _ImageUriCache.default.has(uri); isPreviouslyLoaded && _ImageUriCache.default.add(uri); this._updateImageState(getImageState(uri, isPreviouslyLoaded), hasDefaultSource); } else if (hasDefaultSource && prevProps.defaultSource !== this.props.defaultSource) { this._updateImageState(this._imageState, hasDefaultSource); } if (this._imageState === STATUS_PENDING) { this._createImageLoader(); } }; _proto.componentWillUnmount = function componentWillUnmount() { var uri = resolveAssetUri(this.props.source); _ImageUriCache.default.remove(uri); this._destroyImageLoader(); this._isMounted = false; }; _proto.render = function render() { var shouldDisplaySource = this.state.shouldDisplaySource; var _this$props3 = this.props, accessibilityLabel = _this$props3.accessibilityLabel, accessible = _this$props3.accessible, blurRadius = _this$props3.blurRadius, defaultSource = _this$props3.defaultSource, draggable = _this$props3.draggable, source = _this$props3.source, testID = _this$props3.testID, capInsets = _this$props3.capInsets, onError = _this$props3.onError, onLayout = _this$props3.onLayout, onLoad = _this$props3.onLoad, onLoadEnd = _this$props3.onLoadEnd, onLoadStart = _this$props3.onLoadStart, resizeMethod = _this$props3.resizeMethod, resizeMode = _this$props3.resizeMode, other = _objectWithoutPropertiesLoose(_this$props3, ["accessibilityLabel", "accessible", "blurRadius", "defaultSource", "draggable", "source", "testID", "capInsets", "onError", "onLayout", "onLoad", "onLoadEnd", "onLoadStart", "resizeMethod", "resizeMode"]); if (process.env.NODE_ENV !== 'production') { if (this.props.src) { console.warn('The <Image> component requires a `source` property rather than `src`.'); } if (this.props.children) { throw new Error('The <Image> component cannot contain children. If you want to render content on top of the image, consider using the <ImageBackground> component or absolute positioning.'); } } var selectedSource = shouldDisplaySource ? source : defaultSource; var displayImageUri = resolveAssetUri(selectedSource); var imageSizeStyle = resolveAssetDimensions(selectedSource); var backgroundImage = displayImageUri ? "url(\"" + displayImageUri + "\")" : null; var flatStyle = _objectSpread({}, _StyleSheet.default.flatten(this.props.style)); var finalResizeMode = resizeMode || flatStyle.resizeMode || _ImageResizeMode.default.cover; // CSS filters var filters = []; var tintColor = flatStyle.tintColor; if (flatStyle.filter) { filters.push(flatStyle.filter); } if (blurRadius) { filters.push("blur(" + blurRadius + "px)"); } if (flatStyle.shadowOffset) { var shadowString = (0, _resolveShadowValue.default)(flatStyle); if (shadowString) { filters.push("drop-shadow(" + shadowString + ")"); } } if (flatStyle.tintColor) { filters.push("url(#tint-" + this._filterId + ")"); } // these styles were converted to filters delete flatStyle.shadowColor; delete flatStyle.shadowOpacity; delete flatStyle.shadowOffset; delete flatStyle.shadowRadius; delete flatStyle.tintColor; // these styles are not supported on View delete flatStyle.overlayColor; delete flatStyle.resizeMode; // Accessibility image allows users to trigger the browser's image context menu var hiddenImage = displayImageUri ? (0, _createElement.default)('img', { alt: accessibilityLabel || '', classList: [classes.accessibilityImage], draggable: draggable || false, ref: this._setImageRef, src: displayImageUri }) : null; return _react.default.createElement(_View.default, _extends({}, other, { accessibilityLabel: accessibilityLabel, accessible: accessible, onLayout: this._createLayoutHandler(finalResizeMode), style: [styles.root, this.context.isInAParentText && styles.inline, imageSizeStyle, flatStyle], testID: testID }), _react.default.createElement(_View.default, { style: [styles.image, resizeModeStyles[finalResizeMode], this._getBackgroundSize(finalResizeMode), backgroundImage && { backgroundImage: backgroundImage }, filters.length > 0 && { filter: filters.join(' ') }] }), hiddenImage, createTintColorSVG(tintColor, this._filterId)); }; _proto._createImageLoader = function _createImageLoader() { var source = this.props.source; this._destroyImageLoader(); var uri = resolveAssetUri(source); this._imageRequestId = _ImageLoader.default.load(uri, this._onLoad, this._onError); this._onLoadStart(); }; _proto._destroyImageLoader = function _destroyImageLoader() { if (this._imageRequestId) { _ImageLoader.default.abort(this._imageRequestId); this._imageRequestId = null; } }; _proto._onLoadEnd = function _onLoadEnd() { var onLoadEnd = this.props.onLoadEnd; if (onLoadEnd) { onLoadEnd(); } }; _proto._onLoadStart = function _onLoadStart() { var _this$props4 = this.props, defaultSource = _this$props4.defaultSource, onLoadStart = _this$props4.onLoadStart; this._updateImageState(STATUS_LOADING, defaultSource != null); if (onLoadStart) { onLoadStart(); } }; _proto._updateImageState = function _updateImageState(status, hasDefaultSource) { if (hasDefaultSource === void 0) { hasDefaultSource = false; } this._imageState = status; var shouldDisplaySource = this._imageState === STATUS_LOADED || this._imageState === STATUS_LOADING && !hasDefaultSource; // only triggers a re-render when the image is loading and has no default image (to support PJPEG), loaded, or failed if (shouldDisplaySource !== this.state.shouldDisplaySource) { if (this._isMounted) { this.setState(function () { return { shouldDisplaySource: shouldDisplaySource }; }); } } }; return Image; }(_react.Component); Image.displayName = 'Image'; Image.contextTypes = { isInAParentText: _propTypes.bool }; Image.defaultProps = { style: emptyObject }; Image.propTypes = process.env.NODE_ENV !== "production" ? _objectSpread({}, _ViewPropTypes.default, { blurRadius: _propTypes.number, defaultSource: _ImageSourcePropType.default, draggable: _propTypes.bool, onError: _propTypes.func, onLayout: _propTypes.func, onLoad: _propTypes.func, onLoadEnd: _propTypes.func, onLoadStart: _propTypes.func, resizeMode: (0, _propTypes.oneOf)(Object.keys(_ImageResizeMode.default)), source: _ImageSourcePropType.default, style: (0, _StyleSheetPropType.default)(_ImageStylePropTypes.default), // compatibility with React Native /* eslint-disable react/sort-prop-types */ capInsets: (0, _propTypes.shape)({ top: _propTypes.number, left: _propTypes.number, bottom: _propTypes.number, right: _propTypes.number }), resizeMethod: (0, _propTypes.oneOf)(['auto', 'resize', 'scale']) /* eslint-enable react/sort-prop-types */ }) : {}; var classes = _css.default.create({ accessibilityImage: _objectSpread({}, _StyleSheet.default.absoluteFillObject, { height: '100%', opacity: 0, width: '100%', zIndex: -1 }) }); var styles = _StyleSheet.default.create({ root: { flexBasis: 'auto', overflow: 'hidden', zIndex: 0 }, inline: { display: 'inline-flex' }, image: _objectSpread({}, _StyleSheet.default.absoluteFillObject, { backgroundColor: 'transparent', backgroundPosition: 'center', backgroundRepeat: 'no-repeat', backgroundSize: 'cover', height: '100%', width: '100%', zIndex: -1 }) }); var resizeModeStyles = _StyleSheet.default.create({ center: { backgroundSize: 'auto' }, contain: { backgroundSize: 'contain' }, cover: { backgroundSize: 'cover' }, none: { backgroundPosition: '0 0', backgroundSize: 'auto' }, repeat: { backgroundPosition: '0 0', backgroundRepeat: 'repeat', backgroundSize: 'auto' }, stretch: { backgroundSize: '100% 100%' } }); var _default = (0, _applyNativeMethods.default)(Image); exports.default = _default; module.exports = exports.default;