[change] Image deprecate resizeMode and tintColor styles

The resizeMode and tintColor props should be used instead. The styles
will be removed in a future release.

Fix #2383
This commit is contained in:
Nicolas Gallagher
2022-08-30 14:34:55 -07:00
committed by Nicolas Gallagher
parent 1f5d0925a5
commit 95c8a545a7
7 changed files with 1737 additions and 6123 deletions
+2 -2
View File
@@ -13,11 +13,11 @@
"prop-types": "^15.6.0",
"react": ">=17.0.2",
"react-dom": ">=17.0.2",
"react-native-web": "0.18.8"
"react-native-web": "0.18.9"
},
"devDependencies": {
"babel-loader": "^8.2.5",
"babel-plugin-react-native-web": "0.18.8",
"babel-plugin-react-native-web": "0.18.9",
"css-loader": "^6.7.1",
"style-loader": "^3.3.1",
"url-loader": "^4.1.1",
@@ -329,14 +329,14 @@ exports[`components/Image prop "style" removes other unsupported View styles 1`]
>
<div
class="css-view-175oi2r r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw r-backgroundSize-4gszlv"
style="filter: url(#tint-57);"
style="filter: url(#tint-55);"
/>
<svg
style="position: absolute; height: 0px; visibility: hidden; width: 0px;"
>
<defs>
<filter
id="tint-57"
id="tint-55"
>
<feflood
flood-color="blue"
@@ -351,16 +351,6 @@ exports[`components/Image prop "style" removes other unsupported View styles 1`]
</div>
`;
exports[`components/Image prop "style" supports "resizeMode" property 1`] = `
<div
class="css-view-175oi2r r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
>
<div
class="css-view-175oi2r r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw r-backgroundSize-ehq7j7"
/>
</div>
`;
exports[`components/Image prop "style" supports "shadow" properties (convert to filter) 1`] = `
<div
class="css-view-175oi2r r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
@@ -372,7 +362,18 @@ exports[`components/Image prop "style" supports "shadow" properties (convert to
</div>
`;
exports[`components/Image prop "style" supports "tintcolor" property (convert to filter) 1`] = `
exports[`components/Image prop "testID" 1`] = `
<div
class="css-view-175oi2r r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
data-testid="testID"
>
<div
class="css-view-175oi2r r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw r-backgroundSize-4gszlv"
/>
</div>
`;
exports[`components/Image prop "tintColor" convert to filter 1`] = `
<div
class="css-view-175oi2r r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
>
@@ -405,14 +406,3 @@ exports[`components/Image prop "style" supports "tintcolor" property (convert to
</svg>
</div>
`;
exports[`components/Image prop "testID" 1`] = `
<div
class="css-view-175oi2r r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
data-testid="testID"
>
<div
class="css-view-175oi2r r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw r-backgroundSize-4gszlv"
/>
</div>
`;
@@ -348,11 +348,6 @@ describe('components/Image', () => {
});
describe('prop "style"', () => {
test('supports "resizeMode" property', () => {
const { container } = render(<Image style={{ resizeMode: 'contain' }} />);
expect(container.firstChild).toMatchSnapshot();
});
test('supports "shadow" properties (convert to filter)', () => {
const { container } = render(
<Image
@@ -362,14 +357,6 @@ describe('components/Image', () => {
expect(container.firstChild).toMatchSnapshot();
});
test('supports "tintcolor" property (convert to filter)', () => {
const defaultSource = { uri: 'https://google.com/favicon.ico' };
const { container } = render(
<Image defaultSource={defaultSource} style={{ tintColor: 'red' }} />
);
expect(container.firstChild).toMatchSnapshot();
});
test('removes other unsupported View styles', () => {
const { container } = render(
<Image style={{ overlayColor: 'red', tintColor: 'blue' }} />
@@ -378,6 +365,16 @@ describe('components/Image', () => {
});
});
describe('prop "tintColor"', () => {
test('convert to filter', () => {
const defaultSource = { uri: 'https://google.com/favicon.ico' };
const { container } = render(
<Image defaultSource={defaultSource} tintColor={'red'} />
);
expect(container.firstChild).toMatchSnapshot();
});
});
test('prop "testID"', () => {
const { container } = render(<Image testID="testID" />);
expect(container.firstChild).toMatchSnapshot();
+20 -4
View File
@@ -19,6 +19,7 @@ import PixelRatio from '../PixelRatio';
import StyleSheet from '../StyleSheet';
import TextAncestorContext from '../Text/TextAncestorContext';
import View from '../View';
import { warnOnce } from '../../modules/warnOnce';
export type { ImageProps };
@@ -50,10 +51,23 @@ function createTintColorSVG(tintColor, id) {
) : null;
}
function getFlatStyle(style, blurRadius, filterId) {
function getFlatStyle(style, blurRadius, filterId, tintColorProp) {
const flatStyle = StyleSheet.flatten(style);
const { filter, resizeMode, shadowOffset, tintColor } = flatStyle;
if (flatStyle.resizeMode) {
warnOnce(
'Image.style.resizeMode',
'Image: style.resizeMode is deprecated. Please use props.resizeMode.'
);
}
if (flatStyle.tintColor) {
warnOnce(
'Image.style.tintColor',
'Image: style.tintColor is deprecated. Please use props.tintColor.'
);
}
// Add CSS filters
// React Native exposes these features as props and proprietary styles
const filters = [];
@@ -71,7 +85,7 @@ function getFlatStyle(style, blurRadius, filterId) {
filters.push(`drop-shadow(${shadowString})`);
}
}
if (tintColor && filterId != null) {
if ((tintColorProp || tintColor) && filterId != null) {
filters.push(`url(#tint-${filterId})`);
}
@@ -209,12 +223,14 @@ const Image: React.AbstractComponent<
const requestRef = React.useRef(null);
const shouldDisplaySource =
state === LOADED || (state === LOADING && defaultSource == null);
const [flatStyle, _resizeMode, filter, tintColor] = getFlatStyle(
const [flatStyle, _resizeMode, filter, _tintColor] = getFlatStyle(
style,
blurRadius,
filterRef.current
filterRef.current,
props.tintColor
);
const resizeMode = props.resizeMode || _resizeMode || 'cover';
const tintColor = props.tintColor || _tintColor;
const selectedSource = shouldDisplaySource ? source : defaultSource;
const displayImageUri = resolveAssetUri(selectedSource);
const imageSizeStyle = resolveAssetDimensions(selectedSource);
+3 -1
View File
@@ -98,6 +98,7 @@ export type ImageStyle = {
boxShadow?: string,
filter?: string,
opacity?: number,
// @deprecated
resizeMode?: ResizeMode,
tintColor?: ColorValue
};
@@ -115,5 +116,6 @@ export type ImageProps = {
onProgress?: (e: any) => void,
resizeMode?: ResizeMode,
source?: Source,
style?: GenericStyleProp<ImageStyle>
style?: GenericStyleProp<ImageStyle>,
tintColor?: ColorValue
};
+27
View File
@@ -0,0 +1,27 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
*/
const warnedKeys: { [string]: boolean, ... } = {};
/**
* A simple function that prints a warning message once per session.
*
* @param {string} key - The key used to ensure the message is printed once.
* This should be unique to the callsite.
* @param {string} message - The message to print
*/
export function warnOnce(key: string, message: string) {
if (warnedKeys[key]) {
return;
}
console.warn(message);
warnedKeys[key] = true;
}