[add] support directly requiring image assets

Thanks to IjzerenHein <hrutjes@gmail.com>. See #84
This commit is contained in:
Nicolas Gallagher
2016-03-08 18:03:45 -08:00
parent 77d201988d
commit 6d7d98c149
4 changed files with 72 additions and 16 deletions

View File

@@ -16,6 +16,25 @@ module.exports = {
}
```
## Image assets
In order to require image assets (e.g. `require('assets/myimage.png')`), add
the `url-loader` to the webpack config:
```js
// webpack.config.js
module.exports = {
// ...
module: {
loaders: {
test: /\.(gif|jpe?g|png|svg)$/,
loader: 'url-loader',
query: { name: '[name].[hash:16].[ext]' }
}
}
```
## Web-specific code
Minor platform differences can use the `Platform` module.

View File

@@ -36,6 +36,14 @@ suite('components/Image', () => {
assert(backgroundImage.indexOf(defaultSource.uri) > -1)
})
test('prop "defaultSource" with string value"', () => {
// emulate require-ed asset
const defaultSource = 'https://google.com/favicon.ico'
const dom = utils.renderToDOM(<Image defaultSource={defaultSource} />)
const backgroundImage = dom.style.backgroundImage
assert(backgroundImage.indexOf(defaultSource) > -1)
})
test('prop "onError"', function (done) {
this.timeout(5000)
utils.render(<Image
@@ -50,10 +58,7 @@ suite('components/Image', () => {
test('prop "onLoad"', function (done) {
this.timeout(5000)
utils.render(<Image
onLoad={onLoad}
source={{ uri: 'https://google.com/favicon.ico' }}
/>)
utils.render(<Image onLoad={onLoad} source={{ uri: 'https://google.com/favicon.ico' }} />)
function onLoad(e) {
assert.equal(e.nativeEvent.type, 'load')
done()
@@ -91,7 +96,28 @@ suite('components/Image', () => {
})
})
test('prop "source"')
test('prop "source"', function (done) {
this.timeout(5000)
const source = { uri: 'https://google.com/favicon.ico' }
utils.render(<Image onLoad={onLoad} source={source} />)
function onLoad(e) {
const src = e.nativeEvent.target.src
assert.equal(src, source.uri)
done()
}
})
test('prop "source" with string value', function (done) {
this.timeout(5000)
// emulate require-ed asset
const source = 'https://google.com/favicon.ico'
utils.render(<Image onLoad={onLoad} source={source} />)
function onLoad(e) {
const src = e.nativeEvent.target.src
assert.equal(src, source)
done()
}
})
suite('prop "style"', () => {
test('converts "resizeMode" property', () => {

View File

@@ -1,5 +1,6 @@
/* global window */
import { NativeMethodsDecorator } from '../../modules/NativeMethodsMixin'
import resolveAssetSource from './resolveAssetSource'
import CoreComponent from '../CoreComponent'
import ImageResizeMode from './ImageResizeMode'
import ImageStylePropTypes from './ImageStylePropTypes'
@@ -14,27 +15,32 @@ const STATUS_LOADING = 'LOADING'
const STATUS_PENDING = 'PENDING'
const STATUS_IDLE = 'IDLE'
const ImageSourcePropType = PropTypes.oneOfType([
PropTypes.shape({
uri: PropTypes.string.isRequired
}),
PropTypes.string
])
@NativeMethodsDecorator
export default class Image extends Component {
static propTypes = {
accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
accessible: CoreComponent.propTypes.accessible,
children: PropTypes.any,
defaultSource: PropTypes.object,
defaultSource: ImageSourcePropType,
onError: PropTypes.func,
onLoad: PropTypes.func,
onLoadEnd: PropTypes.func,
onLoadStart: PropTypes.func,
resizeMode: PropTypes.oneOf(['contain', 'cover', 'none', 'stretch']),
source: PropTypes.object,
source: ImageSourcePropType,
style: StyleSheetPropType(ImageStylePropTypes),
testID: CoreComponent.propTypes.testID
};
static defaultProps = {
accessible: true,
defaultSource: {},
source: {},
style: {}
};
@@ -42,7 +48,7 @@ export default class Image extends Component {
constructor(props, context) {
super(props, context)
const { uri } = props.source
const uri = resolveAssetSource(props.source)
// state
this.state = { status: uri ? STATUS_PENDING : STATUS_IDLE }
// autobinding
@@ -51,13 +57,13 @@ export default class Image extends Component {
}
_createImageLoader() {
const { source } = this.props
const uri = resolveAssetSource(this.props.source)
this._destroyImageLoader()
this.image = new window.Image()
this.image.onerror = this._onError
this.image.onload = this._onLoad
this.image.src = source.uri
this.image.src = uri
this._onLoadStart()
}
@@ -113,9 +119,10 @@ export default class Image extends Component {
}
componentWillReceiveProps(nextProps) {
if (this.props.source.uri !== nextProps.source.uri) {
const nextUri = resolveAssetSource(nextProps.source)
if (resolveAssetSource(this.props.source) !== nextUri) {
this.setState({
status: nextProps.source.uri ? STATUS_PENDING : STATUS_IDLE
status: nextUri ? STATUS_PENDING : STATUS_IDLE
})
}
}
@@ -135,8 +142,7 @@ export default class Image extends Component {
} = this.props
const isLoaded = this.state.status === STATUS_LOADED
const defaultImage = defaultSource.uri || null
const displayImage = !isLoaded ? defaultImage : source.uri
const displayImage = resolveAssetSource(!isLoaded ? defaultSource : source)
const backgroundImage = displayImage ? `url("${displayImage}")` : null
const style = StyleSheet.flatten(this.props.style)

View File

@@ -0,0 +1,5 @@
function resolveAssetSource(source) {
return ((typeof source === 'object') ? source.uri : source) || null
}
export default resolveAssetSource