diff --git a/packages/react-native-web/src/exports/Image/__tests__/index-test.js b/packages/react-native-web/src/exports/Image/__tests__/index-test.js index 17b7718b..c7f81d9b 100644 --- a/packages/react-native-web/src/exports/Image/__tests__/index-test.js +++ b/packages/react-native-web/src/exports/Image/__tests__/index-test.js @@ -5,10 +5,13 @@ import Image from '../'; import ImageLoader from '../../../modules/ImageLoader'; import ImageUriCache from '../ImageUriCache'; import React from 'react'; +import StyleSheet from '../../StyleSheet'; import { mount, shallow } from 'enzyme'; const originalImage = window.Image; +const findImageSurfaceStyle = wrapper => StyleSheet.flatten(wrapper.childAt(0).prop('style')); + describe('components/Image', () => { beforeEach(() => { window.Image = jest.fn(() => ({})); @@ -37,14 +40,14 @@ describe('components/Image', () => { test('sets background image when value is an object', () => { const defaultSource = { uri: 'https://google.com/favicon.ico' }; const component = shallow(); - expect(component.prop('style').backgroundImage).toMatchSnapshot(); + expect(findImageSurfaceStyle(component).backgroundImage).toMatchSnapshot(); }); test('sets background image when value is a string', () => { // emulate require-ed asset const defaultSource = 'https://google.com/favicon.ico'; const component = shallow(); - expect(component.prop('style').backgroundImage).toMatchSnapshot(); + expect(findImageSurfaceStyle(component).backgroundImage).toMatchSnapshot(); }); test('sets "height" and "width" styles if missing', () => { @@ -54,7 +57,7 @@ describe('components/Image', () => { width: 20 }; const component = shallow(); - const { height, width } = component.prop('style'); + const { height, width } = StyleSheet.flatten(component.prop('style')); expect(height).toBe(10); expect(width).toBe(20); }); @@ -68,7 +71,7 @@ describe('components/Image', () => { const component = shallow( ); - const { height, width } = component.prop('style'); + const { height, width } = StyleSheet.flatten(component.prop('style')); expect(height).toBe(20); expect(width).toBe(40); }); @@ -141,7 +144,7 @@ describe('components/Image', () => { ].forEach(resizeMode => { test(`value "${resizeMode}"`, () => { const component = shallow(); - expect(component.prop('style').backgroundSize).toMatchSnapshot(); + expect(findImageSurfaceStyle(component).backgroundSize).toMatchSnapshot(); }); }); }); @@ -206,7 +209,7 @@ describe('components/Image', () => { describe('prop "style"', () => { test('correctly supports "resizeMode" property', () => { const component = shallow(); - expect(component.prop('style').backgroundSize).toMatchSnapshot(); + expect(findImageSurfaceStyle(component).backgroundSize).toMatchSnapshot(); }); test('removes other unsupported View styles', () => { diff --git a/packages/react-native-web/src/exports/Image/index.js b/packages/react-native-web/src/exports/Image/index.js index 8b488c98..8e4216b5 100644 --- a/packages/react-native-web/src/exports/Image/index.js +++ b/packages/react-native-web/src/exports/Image/index.js @@ -188,37 +188,6 @@ class Image extends Component<*, State> { ...other } = this.props; - const displayImage = resolveAssetUri(shouldDisplaySource ? source : defaultSource); - const imageSizeStyle = resolveAssetDimensions(shouldDisplaySource ? source : defaultSource); - const backgroundImage = displayImage ? `url("${displayImage}")` : null; - const originalStyle = StyleSheet.flatten(this.props.style); - const finalResizeMode = resizeMode || originalStyle.resizeMode || ImageResizeMode.cover; - - const style = StyleSheet.flatten([ - styles.initial, - imageSizeStyle, - originalStyle, - resizeModeStyles[finalResizeMode], - this.context.isInAParentText && styles.inline, - backgroundImage && { backgroundImage } - ]); - // View doesn't support these styles - delete style.overlayColor; - delete style.resizeMode; - delete style.tintColor; - - // Allows users to trigger the browser's image context menu - const hiddenImage = displayImage - ? createElement('img', { - alt: accessibilityLabel || '', - decode: 'async', - draggable: draggable || false, - ref: this._setImageRef, - src: displayImage, - style: styles.img - }) - : null; - if (process.env.NODE_ENV !== 'production') { if (this.props.src) { console.warn('The component requires a `source` property rather than `src`.'); @@ -231,15 +200,49 @@ class Image extends Component<*, State> { } } + const selectedSource = shouldDisplaySource ? source : defaultSource; + const displayImageUri = resolveAssetUri(selectedSource); + const imageSizeStyle = resolveAssetDimensions(selectedSource); + const backgroundImage = displayImageUri ? `url("${displayImageUri}")` : null; + const flatStyle = { ...StyleSheet.flatten(this.props.style) }; + const finalResizeMode = resizeMode || flatStyle.resizeMode || ImageResizeMode.cover; + // View doesn't support these styles + delete flatStyle.overlayColor; + delete flatStyle.resizeMode; + delete flatStyle.tintColor; + + // Accessibility image allows users to trigger the browser's image context menu + const hiddenImage = displayImageUri + ? createElement('img', { + alt: accessibilityLabel || '', + draggable: draggable || false, + ref: this._setImageRef, + src: displayImageUri, + style: styles.accessibilityImage + }) + : null; + return ( + {hiddenImage} ); @@ -317,17 +320,25 @@ class Image extends Component<*, State> { } const styles = StyleSheet.create({ - initial: { - backgroundColor: 'transparent', - backgroundPosition: 'center', - backgroundRepeat: 'no-repeat', - backgroundSize: 'cover', + root: { + flexBasis: 'auto', + overflow: 'hidden', zIndex: 0 }, inline: { display: 'inline-flex' }, - img: { + image: { + ...StyleSheet.absoluteFillObject, + backgroundColor: 'transparent', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + height: '100%', + width: '100%', + zIndex: -1 + }, + accessibilityImage: { ...StyleSheet.absoluteFillObject, height: '100%', opacity: 0, @@ -338,8 +349,7 @@ const styles = StyleSheet.create({ const resizeModeStyles = StyleSheet.create({ center: { - backgroundSize: 'auto', - backgroundPosition: 'center' + backgroundSize: 'auto' }, contain: { backgroundSize: 'contain' @@ -348,11 +358,13 @@ const resizeModeStyles = StyleSheet.create({ backgroundSize: 'cover' }, none: { + backgroundPosition: '0 0', backgroundSize: 'auto' }, repeat: { - backgroundSize: 'auto', - backgroundRepeat: 'repeat' + backgroundPosition: '0 0', + backgroundRepeat: 'repeat', + backgroundSize: 'auto' }, stretch: { backgroundSize: '100% 100%'