mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-05-12 19:06:35 +00:00
wip
This commit is contained in:
@@ -1,309 +1,302 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`components/Image prop "accessibilityLabel" 1`] = `
|
||||
<div
|
||||
<img
|
||||
aria-label="accessibilityLabel"
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://google.com/favicon.ico);"
|
||||
/>
|
||||
<img
|
||||
alt="accessibilityLabel"
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://google.com/favicon.ico"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "alternativeText" set to empty string 1`] = `
|
||||
<img
|
||||
alt=""
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "alternativeText" set to value 1`] = `
|
||||
<img
|
||||
alt="alternative text"
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "blurRadius" 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://google.com/favicon.ico); filter: blur(5px);"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://google.com/favicon.ico"
|
||||
style="filter: blur(5px); object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "crossOrigin" sets value 1`] = `
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
crossorigin="use-credentials"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "decoding" sets value 1`] = `
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "defaultSource" does not override "height" and "width" styles 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
style="height: 20px; width: 40px;"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://google.com/favicon.ico);"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://google.com/favicon.ico"
|
||||
style="height: 20px; object-fit: cover; width: 40px;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "defaultSource" sets "height" and "width" styles if missing 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
style="height: 10px; width: 20px;"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://google.com/favicon.ico);"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://google.com/favicon.ico"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "defaultSource" sets background image when value is a string 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://google.com/favicon.ico);"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
exports[`components/Image prop "defaultSource" sets image when value is a string 1`] = `
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://google.com/favicon.ico"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "defaultSource" sets background image when value is an object 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://google.com/favicon.ico);"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
exports[`components/Image prop "defaultSource" sets image when value is an object 1`] = `
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://google.com/favicon.ico"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "draggable" 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://google.com/favicon.ico);"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="true"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="true"
|
||||
loading="lazy"
|
||||
src="https://google.com/favicon.ico"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "focusable" 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: cover;"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
/>
|
||||
</div>
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "loading" sets value 1`] = `
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "nativeID" 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
id="nativeID"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
/>
|
||||
</div>
|
||||
loading="lazy"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "onError" is called when image fails to load and replaces src with placeholder 1`] = `
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "onLoad" is called once when image loads 1`] = `
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://google.com/favicon.ico"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "resizeMode" value "contain" 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-ehq7j7 r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: contain;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "resizeMode" value "cover" 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "resizeMode" value "none" 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-p9m3gb r-backgroundRepeat-u6sd8q r-backgroundSize-1sxrcry r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: none;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "resizeMode" value "repeat" 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-p9m3gb r-backgroundRepeat-17leim2 r-backgroundSize-1sxrcry r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "resizeMode" value "stretch" 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-x3cy2q r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: fill;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "resizeMode" value "undefined" 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "source" is correctly updated only when loaded if defaultSource provided 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://testing.com/preview.jpg);"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://testing.com/preview.jpg"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://testing.com/fullSize.jpg"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "source" is correctly updated only when loaded if defaultSource provided 2`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://testing.com/fullSize.jpg);"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://testing.com/fullSize.jpg"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://testing.com/fullSize.jpg"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "source" is correctly updated when missing in initial render 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://testing.com/img.jpg);"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://testing.com/img.jpg"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "source" is not set immediately if the image has not already been loaded 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://google.com/favicon.ico);"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://google.com/favicon.ico"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "source" is set immediately if the image has already been loaded 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://google.com/favicon.ico);"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://google.com/favicon.ico"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "source" is set immediately if the image has already been loaded 2`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://twitter.com/favicon.ico);"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://twitter.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://google.com/favicon.ico"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "source" is set immediately if the image was preloaded 1`] = `
|
||||
@@ -324,61 +317,53 @@ exports[`components/Image prop "source" is set immediately if the image was prel
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "style" removes other unsupported View styles 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="filter: url('data:image/svg+xml,<svg xmlns=\\"http://www.w3.org/2000/svg\\"><filter id=\\"tint\\"><feColorMatrix type=\\"matrix\\" values=\\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1.00 0\\" /></filter></svg>#tint');"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="filter: url('data:image/svg+xml,<svg xmlns=\\"http://www.w3.org/2000/svg\\"><filter id=\\"tint\\"><feColorMatrix type=\\"matrix\\" values=\\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1.00 0\\" /></filter></svg>#tint'); object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "style" supports "resizeMode" property 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-ehq7j7 r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: contain;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "style" supports "shadow" properties (convert to filter) 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="filter: drop-shadow(1px 1px 0px rgba(255,0,0,1.00));"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="filter: drop-shadow(1px 1px 0px rgba(255,0,0,1.00)); object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "style" supports "tintcolor" property (convert to filter) 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
style="background-image: url(https://google.com/favicon.ico); filter: url('data:image/svg+xml,<svg xmlns=\\"http://www.w3.org/2000/svg\\"><filter id=\\"tint\\"><feColorMatrix type=\\"matrix\\" values=\\"0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1.00 0\\" /></filter></svg>#tint');"
|
||||
/>
|
||||
<img
|
||||
alt=""
|
||||
class="css-accessibilityImage-9pa8cd"
|
||||
draggable="false"
|
||||
src="https://google.com/favicon.ico"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
src="https://google.com/favicon.ico"
|
||||
style="filter: url('data:image/svg+xml,<svg xmlns=\\"http://www.w3.org/2000/svg\\"><filter id=\\"tint\\"><feColorMatrix type=\\"matrix\\" values=\\"0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1.00 0\\" /></filter></svg>#tint'); object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/Image prop "testID" 1`] = `
|
||||
<div
|
||||
class="css-view-1dbjc4n r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010"
|
||||
<img
|
||||
class="css-image-tcr4mf"
|
||||
data-testid="testID"
|
||||
>
|
||||
<div
|
||||
class="css-view-1dbjc4n r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-backgroundSize-4gszlv r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw"
|
||||
/>
|
||||
</div>
|
||||
decoding="async"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
style="object-fit: cover;"
|
||||
/>
|
||||
`;
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import * as AssetRegistry from '../../../modules/AssetRegistry';
|
||||
import Image from '../';
|
||||
import ImageLoader, { ImageUriCache } from '../../../modules/ImageLoader';
|
||||
import { ImageUriCache } from '../../../modules/ImageLoader';
|
||||
import PixelRatio from '../../PixelRatio';
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { createEventTarget } from 'dom-event-testing-library';
|
||||
|
||||
const originalImage = window.Image;
|
||||
|
||||
@@ -29,20 +30,48 @@ describe('components/Image', () => {
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('prop "alternativeText"', () => {
|
||||
test('set to empty string', () => {
|
||||
const { container } = render(<Image alternativeText="" />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('set to value', () => {
|
||||
const { container } = render(
|
||||
<Image alternativeText="alternative text" />
|
||||
);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
test('prop "blurRadius"', () => {
|
||||
const defaultSource = { uri: 'https://google.com/favicon.ico' };
|
||||
const { container } = render(<Image blurRadius={5} defaultSource={defaultSource} />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('prop "crossOrigin"', () => {
|
||||
test('sets value', () => {
|
||||
const { container } = render(<Image crossOrigin="use-credentials" />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "decoding"', () => {
|
||||
test('sets value', () => {
|
||||
const { container } = render(<Image decoding="async" />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "defaultSource"', () => {
|
||||
test('sets background image when value is an object', () => {
|
||||
test('sets image when value is an object', () => {
|
||||
const defaultSource = { uri: 'https://google.com/favicon.ico' };
|
||||
const { container } = render(<Image defaultSource={defaultSource} />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('sets background image when value is a string', () => {
|
||||
test('sets image when value is a string', () => {
|
||||
// emulate require-ed asset
|
||||
const defaultSource = 'https://google.com/favicon.ico';
|
||||
const { container } = render(<Image defaultSource={defaultSource} />);
|
||||
@@ -83,151 +112,173 @@ describe('components/Image', () => {
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('prop "loading"', () => {
|
||||
test('sets value', () => {
|
||||
const { container } = render(<Image loading="lazy" />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
test('prop "nativeID"', () => {
|
||||
const { container } = render(<Image nativeID="nativeID" />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('prop "onLoad"', () => {
|
||||
const originalLoad = ImageLoader.load;
|
||||
|
||||
beforeEach(() => {
|
||||
ImageLoader.load = jest.fn().mockImplementation((_, onLoad, onError) => {
|
||||
onLoad();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
ImageLoader.load = originalLoad;
|
||||
});
|
||||
|
||||
test('is not called again if callback changes', () => {
|
||||
const onLoadStub = jest.fn();
|
||||
const onLoadReplacementStub = jest.fn();
|
||||
|
||||
const { rerender } = render(
|
||||
<Image onLoad={onLoadStub} source={'https://test.com/img.jpg'} />
|
||||
);
|
||||
describe('prop "onError"', () => {
|
||||
test('is called when image fails to load and replaces src with placeholder', () => {
|
||||
const onError = jest.fn();
|
||||
const ref = React.createRef();
|
||||
let container;
|
||||
act(() => {
|
||||
rerender(<Image onLoad={onLoadReplacementStub} source={'https://test.com/img.jpg'} />);
|
||||
({ container } = render(
|
||||
<Image onError={onError} ref={ref} source="" />
|
||||
));
|
||||
});
|
||||
expect(onLoadStub.mock.calls.length).toBe(1);
|
||||
expect(onLoadReplacementStub.mock.calls.length).toBe(0);
|
||||
const image = createEventTarget(ref.current);
|
||||
act(() => {
|
||||
image.error();
|
||||
});
|
||||
expect(onError).toBeCalledTimes(1);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
test('is called after image is loaded from network', () => {
|
||||
jest.useFakeTimers();
|
||||
const onLoadStartStub = jest.fn();
|
||||
const onLoadStub = jest.fn();
|
||||
const onLoadEndStub = jest.fn();
|
||||
render(
|
||||
<Image
|
||||
onLoad={onLoadStub}
|
||||
onLoadEnd={onLoadEndStub}
|
||||
onLoadStart={onLoadStartStub}
|
||||
source="https://test.com/img.jpg"
|
||||
/>
|
||||
describe('prop "onLoad"', () => {
|
||||
test('is called once when image loads', () => {
|
||||
const onLoad = jest.fn();
|
||||
const onLoadEnd = jest.fn();
|
||||
const onLoadStart = jest.fn();
|
||||
const ref = React.createRef();
|
||||
let container;
|
||||
act(() => {
|
||||
({ container } = render(
|
||||
<Image
|
||||
onLoad={onLoad}
|
||||
onLoadEnd={onLoadEnd}
|
||||
onLoadStart={onLoadStart}
|
||||
ref={ref}
|
||||
source="https://google.com/favicon.ico"
|
||||
/>
|
||||
));
|
||||
});
|
||||
const image = createEventTarget(ref.current);
|
||||
act(() => {
|
||||
image.load({
|
||||
target: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
naturalWidth: 200,
|
||||
naturalHeight: 200,
|
||||
currentSrc: 'https://google.com/favicon.ico',
|
||||
src: 'https://google.com/favicon.ico'
|
||||
}
|
||||
});
|
||||
});
|
||||
expect(onLoad).toBeCalledTimes(1);
|
||||
expect(onLoadEnd).toBeCalledTimes(1);
|
||||
expect(onLoadStart).toBeCalledTimes(1);
|
||||
expect(onLoad).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
nativeEvent: expect.objectContaining({
|
||||
source: expect.objectContaining({
|
||||
width: expect.any(Number),
|
||||
height: expect.any(Number),
|
||||
url: 'https://google.com/favicon.ico'
|
||||
})
|
||||
})
|
||||
})
|
||||
);
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(onLoadStub).toBeCalled();
|
||||
});
|
||||
|
||||
test('is called after image is loaded from cache', () => {
|
||||
jest.useFakeTimers();
|
||||
const onLoadStartStub = jest.fn();
|
||||
const onLoadStub = jest.fn();
|
||||
const onLoadEndStub = jest.fn();
|
||||
const uri = 'https://test.com/img.jpg';
|
||||
ImageUriCache.add(uri);
|
||||
render(
|
||||
<Image
|
||||
onLoad={onLoadStub}
|
||||
onLoadEnd={onLoadEndStub}
|
||||
onLoadStart={onLoadStartStub}
|
||||
source={uri}
|
||||
/>
|
||||
);
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(onLoadStub).toBeCalled();
|
||||
ImageUriCache.remove(uri);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('is called on update if "uri" is different', () => {
|
||||
const onLoadStartStub = jest.fn();
|
||||
const onLoadStub = jest.fn();
|
||||
const onLoadEndStub = jest.fn();
|
||||
const { rerender } = render(
|
||||
<Image
|
||||
onLoad={onLoadStub}
|
||||
onLoadEnd={onLoadEndStub}
|
||||
onLoadStart={onLoadStartStub}
|
||||
source={'https://test.com/img.jpg'}
|
||||
/>
|
||||
);
|
||||
const ref = React.createRef();
|
||||
act(() => {
|
||||
rerender(
|
||||
<Image
|
||||
onLoad={onLoadStub}
|
||||
onLoadEnd={onLoadEndStub}
|
||||
onLoadStart={onLoadStartStub}
|
||||
source={'https://blah.com/img.png'}
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(onLoadStub.mock.calls.length).toBe(2);
|
||||
expect(onLoadEndStub.mock.calls.length).toBe(2);
|
||||
});
|
||||
|
||||
test('is not called on update if "uri" is the same', () => {
|
||||
const onLoadStartStub = jest.fn();
|
||||
const onLoadStub = jest.fn();
|
||||
const onLoadEndStub = jest.fn();
|
||||
const { rerender } = render(
|
||||
<Image
|
||||
onLoad={onLoadStub}
|
||||
onLoadEnd={onLoadEndStub}
|
||||
onLoadStart={onLoadStartStub}
|
||||
source={'https://test.com/img.jpg'}
|
||||
/>
|
||||
);
|
||||
act(() => {
|
||||
rerender(
|
||||
render(
|
||||
<Image
|
||||
onLoad={onLoadStub}
|
||||
onLoadEnd={onLoadEndStub}
|
||||
onLoadStart={onLoadStartStub}
|
||||
ref={ref}
|
||||
source={'https://test.com/img.jpg'}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const image = createEventTarget(ref.current);
|
||||
act(() => {
|
||||
image.load({
|
||||
target: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
naturalWidth: 200,
|
||||
naturalHeight: 200,
|
||||
currentSrc: 'https://test.com/img.jpg',
|
||||
src: 'https://test.com/img.jpg'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
expect(onLoadStub.mock.calls.length).toBe(1);
|
||||
expect(onLoadEndStub.mock.calls.length).toBe(1);
|
||||
});
|
||||
expect(onLoadStartStub.mock.calls.length).toBe(1);
|
||||
|
||||
test('is not called on update if "uri" is the same and given as an object', () => {
|
||||
const onLoadStartStub = jest.fn();
|
||||
const onLoadStub = jest.fn();
|
||||
const onLoadEndStub = jest.fn();
|
||||
const { rerender } = render(
|
||||
<Image
|
||||
onLoad={onLoadStub}
|
||||
onLoadEnd={onLoadEndStub}
|
||||
onLoadStart={onLoadStartStub}
|
||||
source={{ uri: 'https://test.com/img.jpg', width: 1, height: 1 }}
|
||||
/>
|
||||
);
|
||||
act(() => {
|
||||
rerender(
|
||||
render(
|
||||
<Image
|
||||
onLoad={onLoadStub}
|
||||
onLoadEnd={onLoadEndStub}
|
||||
onLoadStart={onLoadStartStub}
|
||||
source={{ uri: 'https://test.com/img.jpg', width: 1, height: 1 }}
|
||||
ref={ref}
|
||||
source={'https://blah.com/img.png'}
|
||||
/>
|
||||
);
|
||||
});
|
||||
expect(onLoadStub.mock.calls.length).toBe(1);
|
||||
expect(onLoadEndStub.mock.calls.length).toBe(1);
|
||||
act(() => {
|
||||
image.load({
|
||||
target: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
naturalWidth: 200,
|
||||
naturalHeight: 200,
|
||||
currentSrc: 'https://blah.com/img.png',
|
||||
src: 'https://blah.com/img.png'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
expect(onLoadStub.mock.calls.length).toBe(2);
|
||||
expect(onLoadEndStub.mock.calls.length).toBe(2);
|
||||
expect(onLoadStartStub.mock.calls.length).toBe(2);
|
||||
});
|
||||
|
||||
test('is not called when placeholder src is used after error', () => {
|
||||
const onError = jest.fn();
|
||||
const onLoad = jest.fn();
|
||||
const ref = React.createRef();
|
||||
act(() => {
|
||||
render(
|
||||
<Image
|
||||
onError={onError}
|
||||
onLoad={onLoad}
|
||||
ref={ref}
|
||||
source="https://google.com"
|
||||
/>
|
||||
);
|
||||
});
|
||||
const image = createEventTarget(ref.current);
|
||||
act(() => {
|
||||
// Results in placeholder being "loaded"
|
||||
image.error();
|
||||
});
|
||||
expect(onError).toBeCalledTimes(1);
|
||||
act(() => {
|
||||
// Emulate the native "load" event for the placeholder
|
||||
image.load();
|
||||
});
|
||||
expect(onLoad).toBeCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -257,9 +308,9 @@ describe('components/Image', () => {
|
||||
|
||||
test('is set immediately if the image was preloaded', () => {
|
||||
const uri = 'https://yahoo.com/favicon.ico';
|
||||
ImageLoader.load = jest.fn().mockImplementationOnce((_, onLoad, onError) => {
|
||||
onLoad();
|
||||
});
|
||||
//ImageLoader.load = jest.fn().mockImplementationOnce((_, onLoad, onError) => {
|
||||
// onLoad();
|
||||
//});
|
||||
return Image.prefetch(uri).then(() => {
|
||||
const source = { uri };
|
||||
const { container } = render(<Image source={source} />, { disableLifecycleMethods: true });
|
||||
@@ -298,25 +349,21 @@ describe('components/Image', () => {
|
||||
test('is correctly updated only when loaded if defaultSource provided', () => {
|
||||
const defaultUri = 'https://testing.com/preview.jpg';
|
||||
const uri = 'https://testing.com/fullSize.jpg';
|
||||
let loadCallback;
|
||||
ImageLoader.load = jest.fn().mockImplementationOnce((_, onLoad, onError) => {
|
||||
loadCallback = onLoad;
|
||||
});
|
||||
const { container } = render(<Image defaultSource={{ uri: defaultUri }} source={{ uri }} />);
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
act(() => {
|
||||
loadCallback();
|
||||
// loadCallback();
|
||||
});
|
||||
expect(container.firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('it correctly selects the source scale', () => {
|
||||
AssetRegistry.getAssetByID = jest.fn(() => ({
|
||||
AssetRegistry.getAssetByID = () => ({
|
||||
httpServerLocation: 'static',
|
||||
name: 'img',
|
||||
scales: [1, 2, 3],
|
||||
type: 'png'
|
||||
}));
|
||||
});
|
||||
|
||||
PixelRatio.get = jest.fn(() => 1.0);
|
||||
let { container } = render(<Image source={1} />);
|
||||
|
||||
439
packages/react-native-web/src/exports/Image/index.js
vendored
439
packages/react-native-web/src/exports/Image/index.js
vendored
@@ -8,38 +8,58 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type { ImageProps } from './types';
|
||||
import type { ImageProps, ImageStatics } from './types';
|
||||
import type { PlatformMethods } from '../../types';
|
||||
|
||||
import * as React from 'react';
|
||||
import createElement from '../createElement';
|
||||
import css from '../StyleSheet/css';
|
||||
import { getAssetByID } from '../../modules/AssetRegistry';
|
||||
import * as forwardedProps from '../../modules/forwardedProps';
|
||||
import pick from '../../modules/pick';
|
||||
import processColor from '../processColor';
|
||||
import resolveShadowValue from '../StyleSheet/resolveShadowValue';
|
||||
import useElementLayout from '../../modules/useElementLayout';
|
||||
import useMergeRefs from '../../modules/useMergeRefs';
|
||||
import usePlatformMethods from '../../modules/usePlatformMethods';
|
||||
import useResponderEvents from '../../modules/useResponderEvents';
|
||||
import ImageLoader from '../../modules/ImageLoader';
|
||||
import PixelRatio from '../PixelRatio';
|
||||
import StyleSheet from '../StyleSheet';
|
||||
import TextAncestorContext from '../Text/TextAncestorContext';
|
||||
import View from '../View';
|
||||
import processColor from '../processColor';
|
||||
|
||||
export type { ImageProps };
|
||||
import { getAssetByID, getAssetUriByID } from '../../modules/AssetRegistry';
|
||||
|
||||
const ERRORED = 'ERRORED';
|
||||
const LOADED = 'LOADED';
|
||||
const LOADING = 'LOADING';
|
||||
const IDLE = 'IDLE';
|
||||
const emptyObject = {};
|
||||
const forwardPropsList = {
|
||||
...forwardedProps.defaultProps,
|
||||
...forwardedProps.accessibilityProps,
|
||||
...forwardedProps.clickProps,
|
||||
...forwardedProps.focusProps,
|
||||
...forwardedProps.keyboardProps,
|
||||
...forwardedProps.mouseProps,
|
||||
...forwardedProps.touchProps,
|
||||
...forwardedProps.styleProps,
|
||||
crossOrigin: true,
|
||||
decoding: true,
|
||||
draggable: true,
|
||||
loading: true,
|
||||
referrerPolicy: true
|
||||
};
|
||||
|
||||
const pickProps = (props) => pick(props, forwardPropsList);
|
||||
|
||||
const svgDataUriPattern = /^(data:image\/svg\+xml;utf8,)(.*)/;
|
||||
|
||||
function getFlatStyle(style, blurRadius) {
|
||||
const flatStyle = { ...StyleSheet.flatten(style) };
|
||||
function getFlatStyle(style, blurRadius, resizeModeProp) {
|
||||
const initialStyle = StyleSheet.flatten(style) || emptyObject;
|
||||
const objectFitStyle = resizeModeStyles[initialStyle.resizeMode || resizeModeProp || 'cover'];
|
||||
const flatStyle = { ...initialStyle, ...objectFitStyle };
|
||||
const { filter, resizeMode, shadowOffset, tintColor } = flatStyle;
|
||||
|
||||
// Add CSS filters
|
||||
// React Native exposes these features as props and proprietary styles
|
||||
const filters = [];
|
||||
let _filter = null;
|
||||
|
||||
if (filter) {
|
||||
filters.push(filter);
|
||||
}
|
||||
@@ -74,10 +94,6 @@ function getFlatStyle(style, blurRadius) {
|
||||
}
|
||||
}
|
||||
|
||||
if (filters.length > 0) {
|
||||
_filter = filters.join(' ');
|
||||
}
|
||||
|
||||
// These styles are converted to CSS filters applied to the
|
||||
// element displaying the background image.
|
||||
delete flatStyle.blurRadius;
|
||||
@@ -90,40 +106,32 @@ function getFlatStyle(style, blurRadius) {
|
||||
delete flatStyle.overlayColor;
|
||||
delete flatStyle.resizeMode;
|
||||
|
||||
return [flatStyle, resizeMode, _filter];
|
||||
if (filters.length > 0) {
|
||||
flatStyle.filter = filters.join(' ');
|
||||
}
|
||||
|
||||
return flatStyle;
|
||||
}
|
||||
|
||||
function resolveAssetDimensions(source) {
|
||||
if (typeof source === 'number') {
|
||||
const { height, width } = getAssetByID(source);
|
||||
return { height, width };
|
||||
} else if (source != null && !Array.isArray(source) && typeof source === 'object') {
|
||||
const { height, width } = source;
|
||||
return { height, width };
|
||||
function getImageData(image: HTMLImageElement) {
|
||||
const { width, height, currentSrc } = image;
|
||||
return {
|
||||
source: { height, width, url: currentSrc },
|
||||
target: image
|
||||
}
|
||||
}
|
||||
|
||||
function resolveAssetUri(source): ?string {
|
||||
let uri = null;
|
||||
if (typeof source === 'number') {
|
||||
// get the URI from the packager
|
||||
const asset = getAssetByID(source);
|
||||
let scale = asset.scales[0];
|
||||
if (asset.scales.length > 1) {
|
||||
const preferredScale = PixelRatio.get();
|
||||
// Get the scale which is closest to the preferred scale
|
||||
scale = asset.scales.reduce((prev, curr) =>
|
||||
Math.abs(curr - preferredScale) < Math.abs(prev - preferredScale) ? curr : prev
|
||||
);
|
||||
}
|
||||
const scaleSuffix = scale !== 1 ? `@${scale}x` : '';
|
||||
uri = asset ? `${asset.httpServerLocation}/${asset.name}${scaleSuffix}.${asset.type}` : '';
|
||||
uri = getAssetUriByID(source);
|
||||
} else if (typeof source === 'string') {
|
||||
uri = source;
|
||||
} else if (Array.isArray(source)) {
|
||||
uri = source[0].uri;
|
||||
} else if (source && typeof source.uri === 'string') {
|
||||
uri = source.uri;
|
||||
}
|
||||
|
||||
if (uri) {
|
||||
const match = uri.match(svgDataUriPattern);
|
||||
// inline SVG markup may contain characters (e.g., #, ") that need to be escaped
|
||||
@@ -133,36 +141,42 @@ function resolveAssetUri(source): ?string {
|
||||
return `${prefix}${encodedSvg}`;
|
||||
}
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
interface ImageStatics {
|
||||
getSize: (
|
||||
uri: string,
|
||||
success: (width: number, height: number) => void,
|
||||
failure: () => void
|
||||
) => void;
|
||||
prefetch: (uri: string) => Promise<void>;
|
||||
queryCache: (uris: Array<string>) => Promise<{| [uri: string]: 'disk/memory' |}>;
|
||||
}
|
||||
const ERROR_PLACEHOLDER =
|
||||
'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
|
||||
|
||||
const Image: React.AbstractComponent<ImageProps, React.ElementRef<typeof View>> = React.forwardRef(
|
||||
(props, ref) => {
|
||||
const Image: React.AbstractComponent<ImageProps, HTMLImageElement & PlatformMethods> = React.forwardRef(
|
||||
(props, forwardedRef) => {
|
||||
const {
|
||||
accessibilityLabel,
|
||||
blurRadius,
|
||||
defaultSource,
|
||||
draggable,
|
||||
onError,
|
||||
onLayout,
|
||||
onLoad,
|
||||
onLoadEnd,
|
||||
onLoadStart,
|
||||
onMoveShouldSetResponder,
|
||||
onMoveShouldSetResponderCapture,
|
||||
onResponderEnd,
|
||||
onResponderGrant,
|
||||
onResponderMove,
|
||||
onResponderReject,
|
||||
onResponderRelease,
|
||||
onResponderStart,
|
||||
onResponderTerminate,
|
||||
onResponderTerminationRequest,
|
||||
onScrollShouldSetResponder,
|
||||
onScrollShouldSetResponderCapture,
|
||||
onSelectionChangeShouldSetResponder,
|
||||
onSelectionChangeShouldSetResponderCapture,
|
||||
onStartShouldSetResponder,
|
||||
onStartShouldSetResponderCapture,
|
||||
pointerEvents,
|
||||
resizeMode,
|
||||
source,
|
||||
style,
|
||||
...rest
|
||||
style
|
||||
} = props;
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
@@ -173,135 +187,171 @@ const Image: React.AbstractComponent<ImageProps, React.ElementRef<typeof View>>
|
||||
}
|
||||
}
|
||||
|
||||
const [state, updateState] = React.useState(() => {
|
||||
const uri = resolveAssetUri(source);
|
||||
if (uri != null) {
|
||||
const isLoaded = ImageLoader.has(uri);
|
||||
if (isLoaded) {
|
||||
return LOADED;
|
||||
}
|
||||
}
|
||||
return IDLE;
|
||||
const supportedProps = pickProps(props);
|
||||
|
||||
const src = resolveAssetUri(source) || resolveAssetUri(defaultSource);
|
||||
let srcSet;
|
||||
if (Array.isArray(source)) {
|
||||
srcSet = source.map(({ uri, scale }) => `${uri} ${scale || 1}x`);
|
||||
}
|
||||
|
||||
const [managedSrc, setManagedSrc] = React.useState(src);
|
||||
const flatStyle = getFlatStyle(style, blurRadius, resizeMode);
|
||||
|
||||
const hostRef = React.useRef(null);
|
||||
const hasTextAncestor = React.useContext(TextAncestorContext);
|
||||
useElementLayout(hostRef, onLayout);
|
||||
useResponderEvents(hostRef, {
|
||||
onMoveShouldSetResponder,
|
||||
onMoveShouldSetResponderCapture,
|
||||
onResponderEnd,
|
||||
onResponderGrant,
|
||||
onResponderMove,
|
||||
onResponderReject,
|
||||
onResponderRelease,
|
||||
onResponderStart,
|
||||
onResponderTerminate,
|
||||
onResponderTerminationRequest,
|
||||
onScrollShouldSetResponder,
|
||||
onScrollShouldSetResponderCapture,
|
||||
onSelectionChangeShouldSetResponder,
|
||||
onSelectionChangeShouldSetResponderCapture,
|
||||
onStartShouldSetResponder,
|
||||
onStartShouldSetResponderCapture
|
||||
});
|
||||
|
||||
const [layout, updateLayout] = React.useState({});
|
||||
const hasTextAncestor = React.useContext(TextAncestorContext);
|
||||
const hiddenImageRef = React.useRef(null);
|
||||
const requestRef = React.useRef(null);
|
||||
const shouldDisplaySource = state === LOADED || (state === LOADING && defaultSource == null);
|
||||
const [flatStyle, _resizeMode, filter] = getFlatStyle(style, blurRadius);
|
||||
const resizeMode = props.resizeMode || _resizeMode || 'cover';
|
||||
const selectedSource = shouldDisplaySource ? source : defaultSource;
|
||||
const displayImageUri = resolveAssetUri(selectedSource);
|
||||
const imageSizeStyle = resolveAssetDimensions(selectedSource);
|
||||
const backgroundImage = displayImageUri ? `url("${displayImageUri}")` : null;
|
||||
const backgroundSize = getBackgroundSize();
|
||||
|
||||
// Accessibility image allows users to trigger the browser's image context menu
|
||||
const hiddenImage = displayImageUri
|
||||
? createElement('img', {
|
||||
alt: accessibilityLabel || '',
|
||||
classList: [classes.accessibilityImage],
|
||||
draggable: draggable || false,
|
||||
ref: hiddenImageRef,
|
||||
src: displayImageUri
|
||||
})
|
||||
: null;
|
||||
|
||||
function getBackgroundSize(): ?string {
|
||||
if (hiddenImageRef.current != null && (resizeMode === 'center' || resizeMode === 'repeat')) {
|
||||
const { naturalHeight, naturalWidth } = hiddenImageRef.current;
|
||||
const { height, width } = layout;
|
||||
if (naturalHeight && naturalWidth && height && width) {
|
||||
const scaleFactor = Math.min(1, width / naturalWidth, height / naturalHeight);
|
||||
const x = Math.ceil(scaleFactor * naturalWidth);
|
||||
const y = Math.ceil(scaleFactor * naturalHeight);
|
||||
return `${x}px ${y}px`;
|
||||
const internalImageRef = React.useCallback((target) => {
|
||||
const errorListener = function (e) {
|
||||
// If the image fails to load, browsers will display a "broken" icon.
|
||||
// To avoid this we replace the image with a transparent gif.
|
||||
setManagedSrc(ERROR_PLACEHOLDER);
|
||||
if (onError != null) {
|
||||
onError({
|
||||
nativeEvent: {
|
||||
error: `Failed to load resource ${e.target.src} (404)`
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleLayout(e) {
|
||||
if (resizeMode === 'center' || resizeMode === 'repeat' || onLayout) {
|
||||
const { layout } = e.nativeEvent;
|
||||
onLayout && onLayout(e);
|
||||
updateLayout(layout);
|
||||
}
|
||||
}
|
||||
|
||||
// Image loading
|
||||
const uri = resolveAssetUri(source);
|
||||
React.useEffect(() => {
|
||||
abortPendingRequest();
|
||||
|
||||
if (uri != null) {
|
||||
updateState(LOADING);
|
||||
if (onLoadStart) {
|
||||
onLoadStart();
|
||||
if (onLoadEnd != null) {
|
||||
onLoadEnd({ nativeEvent: { target }});
|
||||
}
|
||||
};
|
||||
|
||||
requestRef.current = ImageLoader.load(
|
||||
uri,
|
||||
function load(e) {
|
||||
updateState(LOADED);
|
||||
if (onLoad) {
|
||||
onLoad(e);
|
||||
}
|
||||
if (onLoadEnd) {
|
||||
onLoadEnd();
|
||||
}
|
||||
},
|
||||
function error() {
|
||||
updateState(ERRORED);
|
||||
if (onError) {
|
||||
onError({
|
||||
nativeEvent: {
|
||||
error: `Failed to load resource ${uri} (404)`
|
||||
}
|
||||
});
|
||||
}
|
||||
if (onLoadEnd) {
|
||||
onLoadEnd();
|
||||
}
|
||||
const loadListener = function (e) {
|
||||
const { target: image } = e;
|
||||
if (image.src === ERROR_PLACEHOLDER) {
|
||||
// Prevent the placeholder from triggering a 'load' event that event
|
||||
// listeners would otherwise receive.
|
||||
e.stopImmediatePropagation();
|
||||
} else {
|
||||
if (onLoad != null) {
|
||||
onLoad({
|
||||
nativeEvent: getImageData(image)
|
||||
});
|
||||
}
|
||||
if (onLoadEnd != null) {
|
||||
onLoadEnd({ nativeEvent: { target }});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function abortPendingRequest() {
|
||||
if (requestRef.current != null) {
|
||||
ImageLoader.abort(requestRef.current);
|
||||
requestRef.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
if (target !== null) {
|
||||
// If the image is loaded before JS loads (e.g., SSR), then we manually
|
||||
// call onLoad
|
||||
// console.log(target.complete)
|
||||
if (onLoad != null && target.complete) {
|
||||
onLoad({
|
||||
nativeEvent: getImageData(target)
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
hostRef.current = target;
|
||||
if (onLoadStart != null) {
|
||||
onLoadStart({ nativeEvent: { target }});
|
||||
}
|
||||
target.addEventListener('error', errorListener);
|
||||
target.addEventListener('load', loadListener);
|
||||
} else if (hostRef.current != null) {
|
||||
const node = hostRef.current;
|
||||
node.removeEventListener('error', errorListener);
|
||||
node.removeEventListener('load', loadListener);
|
||||
hostRef.current = null;
|
||||
}
|
||||
},
|
||||
[onError, onLoad, onLoadEnd]
|
||||
);
|
||||
|
||||
return abortPendingRequest;
|
||||
}, [uri, requestRef, updateState, onError, onLoad, onLoadEnd, onLoadStart]);
|
||||
const platformMethodsRef = usePlatformMethods(supportedProps);
|
||||
|
||||
return (
|
||||
<View
|
||||
{...rest}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
onLayout={handleLayout}
|
||||
pointerEvents={pointerEvents}
|
||||
ref={ref}
|
||||
style={[styles.root, hasTextAncestor && styles.inline, imageSizeStyle, flatStyle]}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.image,
|
||||
resizeModeStyles[resizeMode],
|
||||
{ backgroundImage, filter },
|
||||
backgroundSize != null && { backgroundSize }
|
||||
]}
|
||||
/>
|
||||
{hiddenImage}
|
||||
</View>
|
||||
const ref = useMergeRefs(
|
||||
hostRef,
|
||||
internalImageRef,
|
||||
platformMethodsRef,
|
||||
forwardedRef
|
||||
);
|
||||
|
||||
supportedProps.alt = props.alternativeText;
|
||||
supportedProps.classList = hasTextAncestor ? inlineClassList : defaultClassList;
|
||||
supportedProps.decoding = props.decoding || 'async';
|
||||
supportedProps.draggable = props.draggable || false;
|
||||
supportedProps.loading = props.loading || 'lazy';
|
||||
supportedProps.ref = ref;
|
||||
supportedProps.src = managedSrc;
|
||||
supportedProps.srcSet =
|
||||
srcSet != null && managedSrc !== ERROR_PLACEHOLDER
|
||||
? srcSet.join(',')
|
||||
: null;
|
||||
supportedProps.style = flatStyle;
|
||||
|
||||
return createElement('img', supportedProps);
|
||||
}
|
||||
);
|
||||
|
||||
Image.displayName = 'Image';
|
||||
|
||||
const classes = css.create({
|
||||
image: {
|
||||
backgroundColor: 'transparent',
|
||||
border: '0 solid black',
|
||||
boxSizing: 'border-box',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flexShrink: 0,
|
||||
margin: 0,
|
||||
minHeight: 0,
|
||||
minWidth: 0,
|
||||
objectFit: 'cover',
|
||||
padding: 0,
|
||||
position: 'relative',
|
||||
zIndex: 0
|
||||
},
|
||||
inlineImage: {
|
||||
display: 'inline-flex'
|
||||
}
|
||||
});
|
||||
|
||||
const defaultClassList = [classes.image];
|
||||
const inlineClassList = [classes.image, classes.inlineImage];
|
||||
|
||||
const resizeModeStyles = {
|
||||
center: {
|
||||
objectFit: 'scale-down'
|
||||
},
|
||||
contain: {
|
||||
objectFit: 'contain'
|
||||
},
|
||||
cover: {
|
||||
objectFit: 'cover'
|
||||
},
|
||||
none: {
|
||||
objectFit: 'none'
|
||||
},
|
||||
stretch: {
|
||||
objectFit: 'fill'
|
||||
}
|
||||
};
|
||||
|
||||
// $FlowIgnore: This is the correct type, but casting makes it unhappy since the variables aren't defined yet
|
||||
const ImageWithStatics = (Image: React.AbstractComponent<
|
||||
ImageProps,
|
||||
@@ -310,7 +360,7 @@ const ImageWithStatics = (Image: React.AbstractComponent<
|
||||
ImageStatics);
|
||||
|
||||
ImageWithStatics.getSize = function (uri, success, failure) {
|
||||
ImageLoader.getSize(uri, success, failure);
|
||||
return ImageLoader.getSize(uri, success, failure);
|
||||
};
|
||||
|
||||
ImageWithStatics.prefetch = function (uri) {
|
||||
@@ -321,59 +371,6 @@ ImageWithStatics.queryCache = function (uris) {
|
||||
return ImageLoader.queryCache(uris);
|
||||
};
|
||||
|
||||
const classes = css.create({
|
||||
accessibilityImage: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
height: '100%',
|
||||
opacity: 0,
|
||||
width: '100%',
|
||||
zIndex: -1
|
||||
}
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
flexBasis: 'auto',
|
||||
overflow: 'hidden',
|
||||
zIndex: 0
|
||||
},
|
||||
inline: {
|
||||
display: 'inline-flex'
|
||||
},
|
||||
image: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: 'transparent',
|
||||
backgroundPosition: 'center',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundSize: 'cover',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
zIndex: -1
|
||||
}
|
||||
});
|
||||
|
||||
const resizeModeStyles = StyleSheet.create({
|
||||
center: {
|
||||
backgroundSize: 'auto'
|
||||
},
|
||||
contain: {
|
||||
backgroundSize: 'contain'
|
||||
},
|
||||
cover: {
|
||||
backgroundSize: 'cover'
|
||||
},
|
||||
none: {
|
||||
backgroundPosition: '0 0',
|
||||
backgroundSize: 'auto'
|
||||
},
|
||||
repeat: {
|
||||
backgroundPosition: '0 0',
|
||||
backgroundRepeat: 'repeat',
|
||||
backgroundSize: 'auto'
|
||||
},
|
||||
stretch: {
|
||||
backgroundSize: '100% 100%'
|
||||
}
|
||||
});
|
||||
export type { ImageProps };
|
||||
|
||||
export default ImageWithStatics;
|
||||
|
||||
@@ -98,16 +98,36 @@ export type ImageStyle = {
|
||||
|
||||
export type ImageProps = {
|
||||
...ViewProps,
|
||||
alternativeText?: ?string,
|
||||
blurRadius?: number,
|
||||
crossOrigin?: 'anonymous' | 'use-credentials',
|
||||
decoding?: 'auto' | 'async' | 'sync',
|
||||
defaultSource?: Source,
|
||||
draggable?: boolean,
|
||||
loading?: 'eager' | 'lazy',
|
||||
onError?: (e: any) => void,
|
||||
onLayout?: (e: any) => void,
|
||||
onLoad?: (e: any) => void,
|
||||
onLoadEnd?: (e: any) => void,
|
||||
onLoadStart?: (e: any) => void,
|
||||
onProgress?: (e: any) => void,
|
||||
referrerPolicy?:
|
||||
| 'no-referrer'
|
||||
| 'no-referrer-when-downgrade'
|
||||
| 'origin'
|
||||
| 'origin-when-cross-origin'
|
||||
| 'unsafe-url',
|
||||
resizeMode?: ResizeMode,
|
||||
source?: Source,
|
||||
style?: GenericStyleProp<ImageStyle>
|
||||
};
|
||||
|
||||
export interface ImageStatics {
|
||||
getSize: (
|
||||
uri: string,
|
||||
success: (width: number, height: number) => void,
|
||||
failure: () => void
|
||||
) => void;
|
||||
prefetch: (uri: string) => Promise<void>;
|
||||
queryCache: (uris: Array<string>) => Promise<{| [uri: string]: 'disk/memory' |}>;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import PixelRatio from '../../exports/PixelRatio';
|
||||
|
||||
export type PackagerAsset = {
|
||||
__packager_asset: boolean,
|
||||
fileSystemLocation: string,
|
||||
@@ -30,3 +32,18 @@ export function registerAsset(asset: PackagerAsset): number {
|
||||
export function getAssetByID(assetId: number): PackagerAsset {
|
||||
return assets[assetId - 1];
|
||||
}
|
||||
|
||||
export function getAssetUriByID(assetId: number): string {
|
||||
// get the URI from the packager
|
||||
const asset = getAssetByID(assetId);
|
||||
let scale = asset.scales[0];
|
||||
if (asset.scales.length > 1) {
|
||||
const preferredScale = PixelRatio.get();
|
||||
// Get the scale which is closest to the preferred scale
|
||||
scale = asset.scales.reduce((prev, curr) =>
|
||||
Math.abs(curr - preferredScale) < Math.abs(prev - preferredScale) ? curr : prev
|
||||
);
|
||||
}
|
||||
const scaleSuffix = scale !== 1 ? `@${scale}x` : '';
|
||||
return asset ? `${asset.httpServerLocation}/${asset.name}${scaleSuffix}.${asset.type}` : '';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user