2015-09-14 14:35:58 +00:00
/ * *
* Copyright ( c ) 2015 - present , Facebook , Inc .
*
2018-02-17 02:24:55 +00:00
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree .
2015-09-14 14:35:58 +00:00
*
* @ flow
2018-01-15 03:32:26 +00:00
* @ format
2015-09-14 14:35:58 +00:00
* /
2018-05-09 07:47:46 +00:00
2015-09-14 14:35:58 +00:00
'use strict' ;
2018-05-10 22:44:52 +00:00
const ImageStylePropTypes = require ( 'ImageStylePropTypes' ) ;
const NativeMethodsMixin = require ( 'NativeMethodsMixin' ) ;
const NativeModules = require ( 'NativeModules' ) ;
const React = require ( 'React' ) ;
const PropTypes = require ( 'prop-types' ) ;
const ReactNativeViewAttributes = require ( 'ReactNativeViewAttributes' ) ;
const StyleSheet = require ( 'StyleSheet' ) ;
const StyleSheetPropType = require ( 'StyleSheetPropType' ) ;
2018-05-09 07:47:46 +00:00
const TextAncestor = require ( 'TextAncestor' ) ;
2018-05-10 22:44:52 +00:00
const ViewPropTypes = require ( 'ViewPropTypes' ) ;
2015-09-14 14:35:58 +00:00
2018-05-10 22:44:52 +00:00
const createReactClass = require ( 'create-react-class' ) ;
const flattenStyle = require ( 'flattenStyle' ) ;
const merge = require ( 'merge' ) ;
const requireNativeComponent = require ( 'requireNativeComponent' ) ;
const resolveAssetSource = require ( 'resolveAssetSource' ) ;
2015-09-14 14:35:58 +00:00
2018-05-10 22:44:52 +00:00
const { ImageLoader } = NativeModules ;
2016-04-13 14:29:10 +00:00
2018-06-10 22:34:37 +00:00
const RKImage = requireNativeComponent ( 'RCTImageView' ) ;
const RCTTextInlineImage = requireNativeComponent ( 'RCTTextInlineImage' ) ;
2016-07-18 19:07:29 +00:00
let _requestId = 1 ;
function generateRequestId ( ) {
return _requestId ++ ;
}
2015-09-14 14:35:58 +00:00
/ * *
2018-01-30 00:10:49 +00:00
* A React component for displaying different types of images ,
2015-09-14 14:35:58 +00:00
* including network images , static resources , temporary local images , and
2018-01-30 00:10:49 +00:00
* images from local disk , such as the camera roll .
2015-09-14 14:35:58 +00:00
*
2018-01-30 00:10:49 +00:00
* See https : //facebook.github.io/react-native/docs/image.html
2015-09-14 14:35:58 +00:00
* /
2018-05-10 22:44:52 +00:00
const Image = createReactClass ( {
2017-07-07 21:24:25 +00:00
displayName : 'Image' ,
2015-09-14 14:35:58 +00:00
propTypes : {
2017-03-24 07:22:57 +00:00
... ViewPropTypes ,
2016-02-10 03:15:52 +00:00
style : StyleSheetPropType ( ImageStylePropTypes ) ,
2018-01-15 03:32:26 +00:00
/ * *
2018-01-30 00:10:49 +00:00
* See https : //facebook.github.io/react-native/docs/image.html#source
2015-10-09 16:31:51 +00:00
* /
source : PropTypes . oneOfType ( [
PropTypes . shape ( {
uri : PropTypes . string ,
2017-02-18 12:33:59 +00:00
headers : PropTypes . objectOf ( PropTypes . string ) ,
2015-10-09 16:31:51 +00:00
} ) ,
// Opaque type returned by require('./image.jpg')
PropTypes . number ,
2016-06-13 21:04:19 +00:00
// Multiple sources
PropTypes . arrayOf (
PropTypes . shape ( {
uri : PropTypes . string ,
width : PropTypes . number ,
height : PropTypes . number ,
2017-10-03 06:19:31 +00:00
headers : PropTypes . objectOf ( PropTypes . string ) ,
2018-01-15 03:32:26 +00:00
} ) ,
) ,
2016-02-10 03:15:52 +00:00
] ) ,
2017-03-02 15:32:08 +00:00
/ * *
2018-01-15 03:32:26 +00:00
* blurRadius : the blur radius of the blur filter added to the image
2018-01-30 00:10:49 +00:00
*
* See https : //facebook.github.io/react-native/docs/image.html#blurradius
2018-01-15 03:32:26 +00:00
* /
2017-03-02 15:32:08 +00:00
blurRadius : PropTypes . number ,
2018-04-06 22:57:09 +00:00
/ * *
2018-04-19 09:30:39 +00:00
* See https : //facebook.github.io/react-native/docs/image.html#defaultsource
* /
2018-04-06 22:57:09 +00:00
defaultSource : PropTypes . number ,
2015-12-06 23:44:47 +00:00
/ * *
2018-01-30 00:10:49 +00:00
* See https : //facebook.github.io/react-native/docs/image.html#loadingindicatorsource
2015-12-06 23:44:47 +00:00
* /
loadingIndicatorSource : PropTypes . oneOfType ( [
PropTypes . shape ( {
uri : PropTypes . string ,
} ) ,
// Opaque type returned by require('./image.jpg')
PropTypes . number ,
] ) ,
2015-11-16 19:39:19 +00:00
progressiveRenderingEnabled : PropTypes . bool ,
fadeDuration : PropTypes . number ,
2015-11-26 01:06:59 +00:00
/ * *
* Invoked on load start
* /
onLoadStart : PropTypes . func ,
2016-11-15 03:42:34 +00:00
/ * *
* Invoked on load error
* /
onError : PropTypes . func ,
2015-11-26 01:06:59 +00:00
/ * *
* Invoked when load completes successfully
* /
onLoad : PropTypes . func ,
/ * *
* Invoked when load either succeeds or fails
* /
onLoadEnd : PropTypes . func ,
2015-09-14 14:35:58 +00:00
/ * *
* Used to locate this view in end - to - end tests .
* /
testID : PropTypes . string ,
2016-09-09 12:00:52 +00:00
/ * *
* The mechanism that should be used to resize the image when the image ' s dimensions
* differ from the image view ' s dimensions . Defaults to ` auto ` .
*
2018-01-30 00:10:49 +00:00
* See https : //facebook.github.io/react-native/docs/image.html#resizemethod
2016-09-09 12:00:52 +00:00
* /
resizeMethod : PropTypes . oneOf ( [ 'auto' , 'resize' , 'scale' ] ) ,
2016-08-01 07:49:14 +00:00
/ * *
* Determines how to resize the image when the frame doesn ' t match the raw
* image dimensions .
*
2018-01-30 00:10:49 +00:00
* See https : //facebook.github.io/react-native/docs/image.html#resizemode
2016-08-01 07:49:14 +00:00
* /
2018-04-19 09:30:39 +00:00
resizeMode : PropTypes . oneOf ( [
'cover' ,
'contain' ,
'stretch' ,
'repeat' ,
'center' ,
] ) ,
2015-09-14 14:35:58 +00:00
} ,
statics : {
2016-05-21 01:40:59 +00:00
getSize (
url : string ,
success : ( width : number , height : number ) => void ,
2017-04-05 17:16:30 +00:00
failure ? : ( error : any ) => void ,
2016-05-21 01:40:59 +00:00
) {
return ImageLoader . getSize ( url )
. then ( function ( sizes ) {
success ( sizes . width , sizes . height ) ;
} )
2018-01-15 03:32:26 +00:00
. catch (
failure ||
function ( ) {
console . warn ( 'Failed to get size for image: ' + url ) ;
} ,
) ;
2016-05-21 01:40:59 +00:00
} ,
2016-04-13 14:29:10 +00:00
/ * *
* Prefetches a remote image for later use by downloading it to the disk
* cache
2018-01-30 00:10:49 +00:00
*
* See https : //facebook.github.io/react-native/docs/image.html#prefetch
2016-04-13 14:29:10 +00:00
* /
2016-07-18 19:07:29 +00:00
prefetch ( url : string , callback : ? Function ) {
const requestId = generateRequestId ( ) ;
callback && callback ( requestId ) ;
return ImageLoader . prefetchImage ( url , requestId ) ;
} ,
/ * *
2018-01-30 00:10:49 +00:00
* Abort prefetch request .
*
* See https : //facebook.github.io/react-native/docs/image.html#abortprefetch
2016-07-18 19:07:29 +00:00
* /
abortPrefetch ( requestId : number ) {
2016-07-23 07:16:32 +00:00
ImageLoader . abortRequest ( requestId ) ;
2016-04-13 14:29:10 +00:00
} ,
2016-08-31 12:06:10 +00:00
/ * *
* Perform cache interrogation .
*
2018-01-30 00:10:49 +00:00
* See https : //facebook.github.io/react-native/docs/image.html#querycache
2016-08-31 12:06:10 +00:00
* /
2018-01-15 03:32:26 +00:00
async queryCache (
urls : Array < string > ,
) : Promise < Map < string , 'memory' | 'disk' >> {
2016-08-31 12:06:10 +00:00
return await ImageLoader . queryCache ( urls ) ;
2016-11-15 05:01:02 +00:00
} ,
/ * *
2018-01-30 00:10:49 +00:00
* Resolves an asset reference into an object .
*
* See https : //facebook.github.io/react-native/docs/image.html#resolveassetsource
2016-11-15 05:01:02 +00:00
* /
resolveAssetSource : resolveAssetSource ,
2015-09-14 14:35:58 +00:00
} ,
mixins : [ NativeMethodsMixin ] ,
/ * *
* ` NativeMethodsMixin ` will look for this when invoking ` setNativeProps ` . We
2017-09-18 04:26:17 +00:00
* make ` this ` look like an actual native component class .
2015-09-14 14:35:58 +00:00
* /
viewConfig : {
uiViewClassName : 'RCTView' ,
2016-03-01 02:02:11 +00:00
validAttributes : ReactNativeViewAttributes . RCTView ,
2015-09-14 14:35:58 +00:00
} ,
render : function ( ) {
2016-06-13 21:04:19 +00:00
const source = resolveAssetSource ( this . props . source ) ;
2018-04-06 22:57:09 +00:00
const defaultSource = resolveAssetSource ( this . props . defaultSource ) ;
2018-01-15 03:32:26 +00:00
const loadingIndicatorSource = resolveAssetSource (
this . props . loadingIndicatorSource ,
) ;
2015-10-05 10:59:02 +00:00
2016-06-13 21:04:19 +00:00
// As opposed to the ios version, here we render `null` when there is no source, source.uri
// or source array.
2015-10-05 10:59:02 +00:00
if ( source && source . uri === '' ) {
console . warn ( 'source.uri should not be an empty string' ) ;
}
2016-03-04 15:31:38 +00:00
if ( this . props . src ) {
2018-01-15 03:32:26 +00:00
console . warn (
'The <Image> component requires a `source` property rather than `src`.' ,
) ;
2016-03-04 15:31:38 +00:00
}
2017-09-26 04:55:56 +00:00
if ( this . props . children ) {
2018-01-15 03:32:26 +00:00
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.' ,
) ;
2017-09-26 04:55:56 +00:00
}
2018-04-06 22:57:09 +00:00
if ( this . props . defaultSource && this . props . loadingIndicatorSource ) {
throw new Error (
'The <Image> component cannot have defaultSource and loadingIndicatorSource at the same time. Please use either defaultSource or loadingIndicatorSource.' ,
) ;
}
2018-05-09 07:47:46 +00:00
if ( ! source || ( ! source . uri && ! Array . isArray ( source ) ) ) {
return null ;
}
2015-09-14 14:35:58 +00:00
2018-05-09 07:47:46 +00:00
let style ;
let sources ;
if ( source . uri ) {
const { width , height } = source ;
style = flattenStyle ( [ { width , height } , styles . base , this . props . style ] ) ;
sources = [ { uri : source . uri } ] ;
} else {
style = flattenStyle ( [ styles . base , this . props . style ] ) ;
sources = source ;
2015-09-14 14:35:58 +00:00
}
2018-05-09 07:47:46 +00:00
const { onLoadStart , onLoad , onLoadEnd , onError } = this . props ;
const nativeProps = merge ( this . props , {
style ,
shouldNotifyLoadEvents : ! ! ( onLoadStart || onLoad || onLoadEnd || onError ) ,
src : sources ,
headers : source . headers ,
defaultSrc : defaultSource ? defaultSource . uri : null ,
loadingIndicatorSrc : loadingIndicatorSource
? loadingIndicatorSource . uri
: null ,
} ) ;
return (
< TextAncestor . Consumer >
{ hasTextAncestor =>
hasTextAncestor ? (
< RCTTextInlineImage { ... nativeProps } / >
) : (
< RKImage { ... nativeProps } / >
)
}
< / T e x t A n c e s t o r . C o n s u m e r >
) ;
2018-01-15 03:32:26 +00:00
} ,
2015-09-14 14:35:58 +00:00
} ) ;
2018-05-10 22:44:52 +00:00
const styles = StyleSheet . create ( {
2015-09-14 14:35:58 +00:00
base : {
overflow : 'hidden' ,
} ,
} ) ;
module . exports = Image ;