mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
b966d29724
Summary: In 2017, React published v15.5 which extracted the built-in `prop types` to a separate package to reflect the fact that not everybody uses them. In 2018, React Native started to remove `PropTypes` from React Native for the same reason. In 0.68 React Native introduced a deprecation warning which notified users that the change was coming, and in 0.69 we removed the PropTypes entirely. The feedback we've received from the community is that there has not been enough time to migrate libraries off of PropTypes. This has resulted in users needing to patch the React Native package `index.js` file directly to add back the PropTypes, instead of migrating off of them. We can empathize with this fix short term (it unblocks the upgrade) but long term this patch will cause users to miss important changes to `index.js`, and add a maintenance cost for users. Part of the reason there was not enough time is that we didn't do a good job surfacing libraries that were using PropTypes. This means, when you got a deprecation warning, it wasn't clear where the source of the usage was (either in your code or in a library). So even if you wanted to migrate, it was difficult to know where to actually make the change. In the next release, we've made it easier to find call sites using deprecated types by [fixing the code frame in errors](https://github.com/react-native-community/cli/pull/1699) reporting in LogBox, and ensuring that [the app doesn't crash without a warning](https://github.com/facebook/react-native/pull/34650). This should make it easier to identify exactly where the deprecated usage is, so you can migrate it. To help users get off of the patch, and allow more time to migrate, we're walking back the removal of PropTypes, and keeping it as a deprecation for a couple more versions. We ask that you either migrate off PropTypes to a type system like TypeScript, or migrate to the `deprecated-react-native-prop-types` package. Once we feel more confident that the community has migrated and will not need to patch React Native in order to fix this issue, we'll remove the PropTypes again. **If you have any trouble finding the source of the PropType usage, please file an issue so we can help track it down with you.** Changelog: [General][Changed] - Add back deprecated PropTypes Reviewed By: yungsters Differential Revision: D40725705 fbshipit-source-id: 8ce61be30343827efd6dc89a012eeef0b6676deb
276 lines
8.6 KiB
JavaScript
276 lines
8.6 KiB
JavaScript
/**
|
|
* 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
|
|
* @format
|
|
*/
|
|
|
|
import type {ImageStyleProp} from '../StyleSheet/StyleSheet';
|
|
import type {RootTag} from '../Types/RootTagTypes';
|
|
import type {ImageIOS} from './Image.flow';
|
|
import type {ImageProps as ImagePropsType} from './ImageProps';
|
|
|
|
import flattenStyle from '../StyleSheet/flattenStyle';
|
|
import StyleSheet from '../StyleSheet/StyleSheet';
|
|
import ImageAnalyticsTagContext from './ImageAnalyticsTagContext';
|
|
import ImageInjection from './ImageInjection';
|
|
import {getImageSourcesFromImageProps} from './ImageSourceUtils';
|
|
import {convertObjectFitToResizeMode} from './ImageUtils';
|
|
import ImageViewNativeComponent from './ImageViewNativeComponent';
|
|
import NativeImageLoaderIOS from './NativeImageLoaderIOS';
|
|
import resolveAssetSource from './resolveAssetSource';
|
|
import * as React from 'react';
|
|
|
|
function getSize(
|
|
uri: string,
|
|
success: (width: number, height: number) => void,
|
|
failure?: (error: any) => void,
|
|
) {
|
|
NativeImageLoaderIOS.getSize(uri)
|
|
.then(([width, height]) => success(width, height))
|
|
.catch(
|
|
failure ||
|
|
function () {
|
|
console.warn('Failed to get size for image ' + uri);
|
|
},
|
|
);
|
|
}
|
|
|
|
function getSizeWithHeaders(
|
|
uri: string,
|
|
headers: {[string]: string, ...},
|
|
success: (width: number, height: number) => void,
|
|
failure?: (error: any) => void,
|
|
): any {
|
|
return NativeImageLoaderIOS.getSizeWithHeaders(uri, headers)
|
|
.then(function (sizes) {
|
|
success(sizes.width, sizes.height);
|
|
})
|
|
.catch(
|
|
failure ||
|
|
function () {
|
|
console.warn('Failed to get size for image: ' + uri);
|
|
},
|
|
);
|
|
}
|
|
|
|
function prefetchWithMetadata(
|
|
url: string,
|
|
queryRootName: string,
|
|
rootTag?: ?RootTag,
|
|
): any {
|
|
if (NativeImageLoaderIOS.prefetchImageWithMetadata) {
|
|
// number params like rootTag cannot be nullable before TurboModules is available
|
|
return NativeImageLoaderIOS.prefetchImageWithMetadata(
|
|
url,
|
|
queryRootName,
|
|
// NOTE: RootTag type
|
|
// $FlowFixMe[incompatible-call] RootTag: number is incompatible with RootTag
|
|
rootTag ? rootTag : 0,
|
|
);
|
|
} else {
|
|
return NativeImageLoaderIOS.prefetchImage(url);
|
|
}
|
|
}
|
|
|
|
function prefetch(url: string): any {
|
|
return NativeImageLoaderIOS.prefetchImage(url);
|
|
}
|
|
|
|
async function queryCache(
|
|
urls: Array<string>,
|
|
): Promise<{[string]: 'memory' | 'disk' | 'disk/memory', ...}> {
|
|
return await NativeImageLoaderIOS.queryCache(urls);
|
|
}
|
|
|
|
export type ImageComponentStatics = $ReadOnly<{|
|
|
getSize: typeof getSize,
|
|
getSizeWithHeaders: typeof getSizeWithHeaders,
|
|
prefetch: typeof prefetch,
|
|
prefetchWithMetadata: typeof prefetchWithMetadata,
|
|
queryCache: typeof queryCache,
|
|
resolveAssetSource: typeof resolveAssetSource,
|
|
|}>;
|
|
|
|
/**
|
|
* A React component for displaying different types of images,
|
|
* including network images, static resources, temporary local images, and
|
|
* images from local disk, such as the camera roll.
|
|
*
|
|
* See https://reactnative.dev/docs/image
|
|
*/
|
|
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
|
|
* LTI update could not be added via codemod */
|
|
const BaseImage = (props: ImagePropsType, forwardedRef) => {
|
|
const source = getImageSourcesFromImageProps(props) || {
|
|
uri: undefined,
|
|
width: undefined,
|
|
height: undefined,
|
|
};
|
|
|
|
let sources;
|
|
let style: ImageStyleProp;
|
|
if (Array.isArray(source)) {
|
|
style = flattenStyle([styles.base, props.style]) || {};
|
|
sources = source;
|
|
} else {
|
|
const {width = props.width, height = props.height, uri} = source;
|
|
style = flattenStyle([{width, height}, styles.base, props.style]) || {};
|
|
sources = [source];
|
|
|
|
if (uri === '') {
|
|
console.warn('source.uri should not be an empty string');
|
|
}
|
|
}
|
|
|
|
const objectFit =
|
|
// $FlowFixMe[prop-missing]
|
|
style && style.objectFit
|
|
? convertObjectFitToResizeMode(style.objectFit)
|
|
: null;
|
|
const resizeMode =
|
|
// $FlowFixMe[prop-missing]
|
|
objectFit || props.resizeMode || (style && style.resizeMode) || 'cover';
|
|
// $FlowFixMe[prop-missing]
|
|
const tintColor = props.tintColor || style.tintColor;
|
|
|
|
if (props.children != null) {
|
|
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.',
|
|
);
|
|
}
|
|
const {
|
|
'aria-busy': ariaBusy,
|
|
'aria-checked': ariaChecked,
|
|
'aria-disabled': ariaDisabled,
|
|
'aria-expanded': ariaExpanded,
|
|
'aria-selected': ariaSelected,
|
|
height,
|
|
src,
|
|
width,
|
|
...restProps
|
|
} = props;
|
|
|
|
const _accessibilityState = {
|
|
busy: ariaBusy ?? props.accessibilityState?.busy,
|
|
checked: ariaChecked ?? props.accessibilityState?.checked,
|
|
disabled: ariaDisabled ?? props.accessibilityState?.disabled,
|
|
expanded: ariaExpanded ?? props.accessibilityState?.expanded,
|
|
selected: ariaSelected ?? props.accessibilityState?.selected,
|
|
};
|
|
const accessibilityLabel = props['aria-label'] ?? props.accessibilityLabel;
|
|
|
|
return (
|
|
<ImageAnalyticsTagContext.Consumer>
|
|
{analyticTag => {
|
|
return (
|
|
<ImageViewNativeComponent
|
|
accessibilityState={_accessibilityState}
|
|
{...restProps}
|
|
accessible={props.alt !== undefined ? true : props.accessible}
|
|
accessibilityLabel={accessibilityLabel ?? props.alt}
|
|
ref={forwardedRef}
|
|
style={style}
|
|
resizeMode={resizeMode}
|
|
tintColor={tintColor}
|
|
source={sources}
|
|
internal_analyticTag={analyticTag}
|
|
/>
|
|
);
|
|
}}
|
|
</ImageAnalyticsTagContext.Consumer>
|
|
);
|
|
};
|
|
|
|
const ImageForwardRef = React.forwardRef<
|
|
ImagePropsType,
|
|
React.ElementRef<typeof ImageViewNativeComponent>,
|
|
>(BaseImage);
|
|
|
|
let Image = ImageForwardRef;
|
|
if (ImageInjection.unstable_createImageComponent != null) {
|
|
Image = ImageInjection.unstable_createImageComponent(Image);
|
|
}
|
|
|
|
Image.displayName = 'Image';
|
|
|
|
/**
|
|
* Retrieve the width and height (in pixels) of an image prior to displaying it.
|
|
*
|
|
* See https://reactnative.dev/docs/image#getsize
|
|
*/
|
|
/* $FlowFixMe[prop-missing] (>=0.89.0 site=react_native_ios_fb) This comment
|
|
* suppresses an error found when Flow v0.89 was deployed. To see the error,
|
|
* delete this comment and run Flow. */
|
|
Image.getSize = getSize;
|
|
|
|
/**
|
|
* Retrieve the width and height (in pixels) of an image prior to displaying it
|
|
* with the ability to provide the headers for the request.
|
|
*
|
|
* See https://reactnative.dev/docs/image#getsizewithheaders
|
|
*/
|
|
/* $FlowFixMe[prop-missing] (>=0.89.0 site=react_native_ios_fb) This comment
|
|
* suppresses an error found when Flow v0.89 was deployed. To see the error,
|
|
* delete this comment and run Flow. */
|
|
Image.getSizeWithHeaders = getSizeWithHeaders;
|
|
|
|
/**
|
|
* Prefetches a remote image for later use by downloading it to the disk
|
|
* cache.
|
|
*
|
|
* See https://reactnative.dev/docs/image#prefetch
|
|
*/
|
|
/* $FlowFixMe[prop-missing] (>=0.89.0 site=react_native_ios_fb) This comment
|
|
* suppresses an error found when Flow v0.89 was deployed. To see the error,
|
|
* delete this comment and run Flow. */
|
|
Image.prefetch = prefetch;
|
|
|
|
/**
|
|
* Prefetches a remote image for later use by downloading it to the disk
|
|
* cache, and adds metadata for queryRootName and rootTag.
|
|
*
|
|
* See https://reactnative.dev/docs/image#prefetch
|
|
*/
|
|
/* $FlowFixMe[prop-missing] (>=0.89.0 site=react_native_ios_fb) This comment
|
|
* suppresses an error found when Flow v0.89 was deployed. To see the error,
|
|
* delete this comment and run Flow. */
|
|
Image.prefetchWithMetadata = prefetchWithMetadata;
|
|
|
|
/**
|
|
* Performs cache interrogation.
|
|
*
|
|
* See https://reactnative.dev/docs/image#querycache
|
|
*/
|
|
/* $FlowFixMe[prop-missing] (>=0.89.0 site=react_native_ios_fb) This comment
|
|
* suppresses an error found when Flow v0.89 was deployed. To see the error,
|
|
* delete this comment and run Flow. */
|
|
Image.queryCache = queryCache;
|
|
|
|
/**
|
|
* Resolves an asset reference into an object.
|
|
*
|
|
* See https://reactnative.dev/docs/image#resolveassetsource
|
|
*/
|
|
/* $FlowFixMe[prop-missing] (>=0.89.0 site=react_native_ios_fb) This comment
|
|
* suppresses an error found when Flow v0.89 was deployed. To see the error,
|
|
* delete this comment and run Flow. */
|
|
Image.resolveAssetSource = resolveAssetSource;
|
|
|
|
/**
|
|
* Switch to `deprecated-react-native-prop-types` for compatibility with future
|
|
* releases. This is deprecated and will be removed in the future.
|
|
*/
|
|
Image.propTypes = require('deprecated-react-native-prop-types').ImagePropTypes;
|
|
|
|
const styles = StyleSheet.create({
|
|
base: {
|
|
overflow: 'hidden',
|
|
},
|
|
});
|
|
|
|
module.exports = ((Image: any): ImageIOS);
|