expo-image 1.10.4 → 1.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,18 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 1.10.6 — 2024-02-06
14
+
15
+ ### 🐛 Bug fixes
16
+
17
+ - Fixed ResizeObserver attaching on every image transition. ([#25819](https://github.com/expo/expo/pull/25819) by [@aleqsio](https://github.com/aleqsio))
18
+
19
+ ## 1.10.5 — 2024-01-23
20
+
21
+ ### 🐛 Bug fixes
22
+
23
+ - [Web] Fixed `nativeViewRef` invalid prop warning. ([#25922](https://github.com/expo/expo/pull/25922) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
24
+
13
25
  ## 1.10.4 — 2024-01-18
14
26
 
15
27
  _This version does not introduce any user-facing changes._
@@ -67,7 +67,7 @@ android {
67
67
  namespace "expo.modules.image"
68
68
  defaultConfig {
69
69
  versionCode 1
70
- versionName "1.10.4"
70
+ versionName "1.10.6"
71
71
  consumerProguardFiles("proguard-rules.pro")
72
72
 
73
73
  buildConfigField("boolean", "ALLOW_GLIDE_LOGS", project.properties.get("EXPO_ALLOW_GLIDE_LOGS", "false"))
@@ -4,5 +4,5 @@ export declare const ExpoImageModule: {
4
4
  clearMemoryCache(): Promise<boolean>;
5
5
  clearDiskCache(): Promise<boolean>;
6
6
  };
7
- export default function ExpoImage({ source, placeholder, contentFit, contentPosition, placeholderContentFit, cachePolicy, onLoad, transition, onError, responsivePolicy, onLoadEnd, priority, blurRadius, recyclingKey, style, ...props }: ImageNativeProps): JSX.Element;
7
+ export default function ExpoImage({ source, placeholder, contentFit, contentPosition, placeholderContentFit, cachePolicy, onLoad, transition, onError, responsivePolicy, onLoadEnd, priority, blurRadius, recyclingKey, style, nativeViewRef, ...props }: ImageNativeProps): JSX.Element;
8
8
  //# sourceMappingURL=ExpoImage.web.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoImage.web.d.ts","sourceRoot":"","sources":["../src/ExpoImage.web.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAmC,MAAM,eAAe,CAAC;AAQlF,eAAO,MAAM,eAAe;mBACL,MAAM,GAAG,MAAM,EAAE,WAAM,QAAQ,OAAO,CAAC;wBAqBlC,QAAQ,OAAO,CAAC;sBAIlB,QAAQ,OAAO,CAAC;CAGzC,CAAC;AA+BF,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAChC,MAAM,EACN,WAAW,EACX,UAAU,EACV,eAAe,EACf,qBAAqB,EACrB,WAAW,EACX,MAAM,EACN,UAAU,EACV,OAAO,EACP,gBAAgB,EAChB,SAAS,EACT,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,KAAK,EACL,GAAG,KAAK,EACT,EAAE,gBAAgB,eA+ElB"}
1
+ {"version":3,"file":"ExpoImage.web.d.ts","sourceRoot":"","sources":["../src/ExpoImage.web.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAmC,MAAM,eAAe,CAAC;AAQlF,eAAO,MAAM,eAAe;mBACL,MAAM,GAAG,MAAM,EAAE,WAAM,QAAQ,OAAO,CAAC;wBAqBlC,QAAQ,OAAO,CAAC;sBAIlB,QAAQ,OAAO,CAAC;CAGzC,CAAC;AAwCF,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAChC,MAAM,EACN,WAAW,EACX,UAAU,EACV,eAAe,EACf,qBAAqB,EACrB,WAAW,EACX,MAAM,EACN,UAAU,EACV,OAAO,EACP,gBAAgB,EAChB,SAAS,EACT,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,KAAK,EACL,aAAa,EACb,GAAG,KAAK,EACT,EAAE,gBAAgB,eAiFlB"}
@@ -51,22 +51,28 @@ function onErrorAdapter(onError) {
51
51
  });
52
52
  };
53
53
  }
54
- // Used for some transitions to mimic native animations
55
- const setCssVariables = (element, size) => {
54
+ // Used for flip transitions to mimic native animations
55
+ function setCssVariablesForFlipTransitions(element, size) {
56
56
  element?.style.setProperty('--expo-image-width', `${size.width}px`);
57
57
  element?.style.setProperty('--expo-image-height', `${size.height}px`);
58
- };
59
- export default function ExpoImage({ source, placeholder, contentFit, contentPosition, placeholderContentFit, cachePolicy, onLoad, transition, onError, responsivePolicy, onLoadEnd, priority, blurRadius, recyclingKey, style, ...props }) {
58
+ }
59
+ function isFlipTransition(transition) {
60
+ return (transition?.effect === 'flip-from-bottom' ||
61
+ transition?.effect === 'flip-from-top' ||
62
+ transition?.effect === 'flip-from-left' ||
63
+ transition?.effect === 'flip-from-right');
64
+ }
65
+ export default function ExpoImage({ source, placeholder, contentFit, contentPosition, placeholderContentFit, cachePolicy, onLoad, transition, onError, responsivePolicy, onLoadEnd, priority, blurRadius, recyclingKey, style, nativeViewRef, ...props }) {
60
66
  const imagePlaceholderContentFit = placeholderContentFit || 'scale-down';
61
67
  const imageHashStyle = {
62
68
  objectFit: placeholderContentFit || contentFit,
63
69
  };
64
- const { containerRef, source: selectedSource } = useSourceSelection(source, responsivePolicy, setCssVariables);
70
+ const { containerRef, source: selectedSource } = useSourceSelection(source, responsivePolicy, isFlipTransition(transition) ? setCssVariablesForFlipTransitions : null);
65
71
  const initialNodeAnimationKey = (recyclingKey ? `${recyclingKey}-${placeholder?.[0]?.uri}` : placeholder?.[0]?.uri) ?? '';
66
72
  const initialNode = placeholder?.[0]?.uri
67
73
  ? [
68
74
  initialNodeAnimationKey,
69
- ({ onAnimationFinished }) => (className, style) => (<ImageWrapper {...props} source={placeholder?.[0]} style={{
75
+ ({ onAnimationFinished }) => (className, style) => (<ImageWrapper {...props} ref={nativeViewRef} source={placeholder?.[0]} style={{
70
76
  objectFit: imagePlaceholderContentFit,
71
77
  ...(blurRadius ? { filter: `blur(${blurRadius}px)` } : {}),
72
78
  ...style,
@@ -80,7 +86,7 @@ export default function ExpoImage({ source, placeholder, contentFit, contentPosi
80
86
  : selectedSource?.uri ?? placeholder?.[0]?.uri) ?? '';
81
87
  const currentNode = [
82
88
  currentNodeAnimationKey,
83
- ({ onAnimationFinished, onReady, onMount, onError: onErrorInner }) => (className, style) => (<ImageWrapper {...props} source={selectedSource || placeholder?.[0]} events={{
89
+ ({ onAnimationFinished, onReady, onMount, onError: onErrorInner }) => (className, style) => (<ImageWrapper {...props} ref={nativeViewRef} source={selectedSource || placeholder?.[0]} events={{
84
90
  onError: [onErrorAdapter(onError), onLoadEnd, onErrorInner],
85
91
  onLoad: [onLoadAdapter(onLoad), onLoadEnd, onReady],
86
92
  onMount: [onMount],
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoImage.web.js","sourceRoot":"","sources":["../src/ExpoImage.web.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { View } from 'react-native-web';\n\nimport { ImageNativeProps, ImageSource, ImageLoadEventData } from './Image.types';\nimport AnimationManager, { AnimationManagerNode } from './web/AnimationManager';\nimport ImageWrapper from './web/ImageWrapper';\nimport loadStyle from './web/imageStyles';\nimport useSourceSelection from './web/useSourceSelection';\n\nloadStyle();\n\nexport const ExpoImageModule = {\n async prefetch(urls: string | string[], _): Promise<boolean> {\n const urlsArray = Array.isArray(urls) ? urls : [urls];\n\n return new Promise<boolean>((resolve) => {\n let imagesLoaded = 0;\n\n urlsArray.forEach((url) => {\n const img = new Image();\n img.src = url;\n img.onload = () => {\n imagesLoaded++;\n\n if (imagesLoaded === urlsArray.length) {\n resolve(true);\n }\n };\n img.onerror = () => resolve(false);\n });\n });\n },\n\n async clearMemoryCache(): Promise<boolean> {\n return false;\n },\n\n async clearDiskCache(): Promise<boolean> {\n return false;\n },\n};\n\nfunction onLoadAdapter(onLoad?: (event: ImageLoadEventData) => void) {\n return (event: React.SyntheticEvent<HTMLImageElement, Event>) => {\n const target = event.target as HTMLImageElement;\n onLoad?.({\n source: {\n url: target.currentSrc,\n width: target.naturalWidth,\n height: target.naturalHeight,\n mediaType: null,\n },\n cacheType: 'none',\n });\n };\n}\n\nfunction onErrorAdapter(onError?: { (event: { error: string }): void }) {\n return ({ source }: { source?: ImageSource | null }) => {\n onError?.({\n error: `Failed to load image from url: ${source?.uri}`,\n });\n };\n}\n\n// Used for some transitions to mimic native animations\nconst setCssVariables = (element: HTMLElement, size: DOMRect) => {\n element?.style.setProperty('--expo-image-width', `${size.width}px`);\n element?.style.setProperty('--expo-image-height', `${size.height}px`);\n};\n\nexport default function ExpoImage({\n source,\n placeholder,\n contentFit,\n contentPosition,\n placeholderContentFit,\n cachePolicy,\n onLoad,\n transition,\n onError,\n responsivePolicy,\n onLoadEnd,\n priority,\n blurRadius,\n recyclingKey,\n style,\n ...props\n}: ImageNativeProps) {\n const imagePlaceholderContentFit = placeholderContentFit || 'scale-down';\n const imageHashStyle = {\n objectFit: placeholderContentFit || contentFit,\n };\n const { containerRef, source: selectedSource } = useSourceSelection(\n source,\n responsivePolicy,\n setCssVariables\n );\n\n const initialNodeAnimationKey =\n (recyclingKey ? `${recyclingKey}-${placeholder?.[0]?.uri}` : placeholder?.[0]?.uri) ?? '';\n\n const initialNode: AnimationManagerNode | null = placeholder?.[0]?.uri\n ? [\n initialNodeAnimationKey,\n ({ onAnimationFinished }) =>\n (className, style) => (\n <ImageWrapper\n {...props}\n source={placeholder?.[0]}\n style={{\n objectFit: imagePlaceholderContentFit,\n ...(blurRadius ? { filter: `blur(${blurRadius}px)` } : {}),\n ...style,\n }}\n className={className}\n events={{\n onTransitionEnd: [onAnimationFinished],\n }}\n contentPosition={{ left: '50%', top: '50%' }}\n hashPlaceholderContentPosition={contentPosition}\n hashPlaceholderStyle={imageHashStyle}\n />\n ),\n ]\n : null;\n\n const currentNodeAnimationKey =\n (recyclingKey\n ? `${recyclingKey}-${selectedSource?.uri ?? placeholder?.[0]?.uri}`\n : selectedSource?.uri ?? placeholder?.[0]?.uri) ?? '';\n\n const currentNode: AnimationManagerNode = [\n currentNodeAnimationKey,\n ({ onAnimationFinished, onReady, onMount, onError: onErrorInner }) =>\n (className, style) => (\n <ImageWrapper\n {...props}\n source={selectedSource || placeholder?.[0]}\n events={{\n onError: [onErrorAdapter(onError), onLoadEnd, onErrorInner],\n onLoad: [onLoadAdapter(onLoad), onLoadEnd, onReady],\n onMount: [onMount],\n onTransitionEnd: [onAnimationFinished],\n }}\n style={{\n objectFit: selectedSource ? contentFit : imagePlaceholderContentFit,\n ...(blurRadius ? { filter: `blur(${blurRadius}px)` } : {}),\n ...style,\n }}\n className={className}\n cachePolicy={cachePolicy}\n priority={priority}\n contentPosition={selectedSource ? contentPosition : { top: '50%', left: '50%' }}\n hashPlaceholderContentPosition={contentPosition}\n hashPlaceholderStyle={imageHashStyle}\n accessibilityLabel={props.accessibilityLabel}\n />\n ),\n ];\n return (\n <View ref={containerRef} dataSet={{ expoimage: true }} style={[{ overflow: 'hidden' }, style]}>\n <AnimationManager transition={transition} recyclingKey={recyclingKey} initial={initialNode}>\n {currentNode}\n </AnimationManager>\n </View>\n );\n}\n"]}
1
+ {"version":3,"file":"ExpoImage.web.js","sourceRoot":"","sources":["../src/ExpoImage.web.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { View } from 'react-native-web';\n\nimport { ImageNativeProps, ImageSource, ImageLoadEventData } from './Image.types';\nimport AnimationManager, { AnimationManagerNode } from './web/AnimationManager';\nimport ImageWrapper from './web/ImageWrapper';\nimport loadStyle from './web/imageStyles';\nimport useSourceSelection from './web/useSourceSelection';\n\nloadStyle();\n\nexport const ExpoImageModule = {\n async prefetch(urls: string | string[], _): Promise<boolean> {\n const urlsArray = Array.isArray(urls) ? urls : [urls];\n\n return new Promise<boolean>((resolve) => {\n let imagesLoaded = 0;\n\n urlsArray.forEach((url) => {\n const img = new Image();\n img.src = url;\n img.onload = () => {\n imagesLoaded++;\n\n if (imagesLoaded === urlsArray.length) {\n resolve(true);\n }\n };\n img.onerror = () => resolve(false);\n });\n });\n },\n\n async clearMemoryCache(): Promise<boolean> {\n return false;\n },\n\n async clearDiskCache(): Promise<boolean> {\n return false;\n },\n};\n\nfunction onLoadAdapter(onLoad?: (event: ImageLoadEventData) => void) {\n return (event: React.SyntheticEvent<HTMLImageElement, Event>) => {\n const target = event.target as HTMLImageElement;\n onLoad?.({\n source: {\n url: target.currentSrc,\n width: target.naturalWidth,\n height: target.naturalHeight,\n mediaType: null,\n },\n cacheType: 'none',\n });\n };\n}\n\nfunction onErrorAdapter(onError?: { (event: { error: string }): void }) {\n return ({ source }: { source?: ImageSource | null }) => {\n onError?.({\n error: `Failed to load image from url: ${source?.uri}`,\n });\n };\n}\n\n// Used for flip transitions to mimic native animations\nfunction setCssVariablesForFlipTransitions(element: HTMLElement, size: DOMRect) {\n element?.style.setProperty('--expo-image-width', `${size.width}px`);\n element?.style.setProperty('--expo-image-height', `${size.height}px`);\n}\n\nfunction isFlipTransition(transition: ImageNativeProps['transition']) {\n return (\n transition?.effect === 'flip-from-bottom' ||\n transition?.effect === 'flip-from-top' ||\n transition?.effect === 'flip-from-left' ||\n transition?.effect === 'flip-from-right'\n );\n}\n\nexport default function ExpoImage({\n source,\n placeholder,\n contentFit,\n contentPosition,\n placeholderContentFit,\n cachePolicy,\n onLoad,\n transition,\n onError,\n responsivePolicy,\n onLoadEnd,\n priority,\n blurRadius,\n recyclingKey,\n style,\n nativeViewRef,\n ...props\n}: ImageNativeProps) {\n const imagePlaceholderContentFit = placeholderContentFit || 'scale-down';\n const imageHashStyle = {\n objectFit: placeholderContentFit || contentFit,\n };\n const { containerRef, source: selectedSource } = useSourceSelection(\n source,\n responsivePolicy,\n isFlipTransition(transition) ? setCssVariablesForFlipTransitions : null\n );\n\n const initialNodeAnimationKey =\n (recyclingKey ? `${recyclingKey}-${placeholder?.[0]?.uri}` : placeholder?.[0]?.uri) ?? '';\n\n const initialNode: AnimationManagerNode | null = placeholder?.[0]?.uri\n ? [\n initialNodeAnimationKey,\n ({ onAnimationFinished }) =>\n (className, style) => (\n <ImageWrapper\n {...props}\n ref={nativeViewRef as React.Ref<HTMLImageElement> | undefined}\n source={placeholder?.[0]}\n style={{\n objectFit: imagePlaceholderContentFit,\n ...(blurRadius ? { filter: `blur(${blurRadius}px)` } : {}),\n ...style,\n }}\n className={className}\n events={{\n onTransitionEnd: [onAnimationFinished],\n }}\n contentPosition={{ left: '50%', top: '50%' }}\n hashPlaceholderContentPosition={contentPosition}\n hashPlaceholderStyle={imageHashStyle}\n />\n ),\n ]\n : null;\n\n const currentNodeAnimationKey =\n (recyclingKey\n ? `${recyclingKey}-${selectedSource?.uri ?? placeholder?.[0]?.uri}`\n : selectedSource?.uri ?? placeholder?.[0]?.uri) ?? '';\n\n const currentNode: AnimationManagerNode = [\n currentNodeAnimationKey,\n ({ onAnimationFinished, onReady, onMount, onError: onErrorInner }) =>\n (className, style) => (\n <ImageWrapper\n {...props}\n ref={nativeViewRef as React.Ref<HTMLImageElement> | undefined}\n source={selectedSource || placeholder?.[0]}\n events={{\n onError: [onErrorAdapter(onError), onLoadEnd, onErrorInner],\n onLoad: [onLoadAdapter(onLoad), onLoadEnd, onReady],\n onMount: [onMount],\n onTransitionEnd: [onAnimationFinished],\n }}\n style={{\n objectFit: selectedSource ? contentFit : imagePlaceholderContentFit,\n ...(blurRadius ? { filter: `blur(${blurRadius}px)` } : {}),\n ...style,\n }}\n className={className}\n cachePolicy={cachePolicy}\n priority={priority}\n contentPosition={selectedSource ? contentPosition : { top: '50%', left: '50%' }}\n hashPlaceholderContentPosition={contentPosition}\n hashPlaceholderStyle={imageHashStyle}\n accessibilityLabel={props.accessibilityLabel}\n />\n ),\n ];\n return (\n <View ref={containerRef} dataSet={{ expoimage: true }} style={[{ overflow: 'hidden' }, style]}>\n <AnimationManager transition={transition} recyclingKey={recyclingKey} initial={initialNode}>\n {currentNode}\n </AnimationManager>\n </View>\n );\n}\n"]}
@@ -9,6 +9,6 @@ type UseSourceSelectionReturn = {
9
9
  containerRef: (element: HTMLDivElement) => void;
10
10
  source: ImageSource | SrcSetSource | null;
11
11
  };
12
- export default function useSourceSelection(sources?: ImageSource[], responsivePolicy?: ImageProps['responsivePolicy'], measurementCallback?: (target: HTMLElement, size: DOMRect) => void): UseSourceSelectionReturn;
12
+ export default function useSourceSelection(sources?: ImageSource[], responsivePolicy?: ImageProps['responsivePolicy'], measurementCallback?: ((target: HTMLElement, size: DOMRect) => void) | null): UseSourceSelectionReturn;
13
13
  export {};
14
14
  //# sourceMappingURL=useSourceSelection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSourceSelection.d.ts","sourceRoot":"","sources":["../../src/web/useSourceSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAoCzD,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IAEd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,CAAC;CAChB;AAmDD,KAAK,wBAAwB,GAAG;IAC9B,YAAY,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAChD,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,IAAI,CAAC;CAC3C,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,kBAAkB,CACxC,OAAO,CAAC,EAAE,WAAW,EAAE,EACvB,gBAAgB,GAAE,UAAU,CAAC,kBAAkB,CAAY,EAC3D,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,GACjE,wBAAwB,CA8C1B"}
1
+ {"version":3,"file":"useSourceSelection.d.ts","sourceRoot":"","sources":["../../src/web/useSourceSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAoCzD,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IAEd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,CAAC;CAChB;AAmDD,KAAK,wBAAwB,GAAG;IAC9B,YAAY,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAChD,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,IAAI,CAAC;CAC3C,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,kBAAkB,CACxC,OAAO,CAAC,EAAE,WAAW,EAAE,EACvB,gBAAgB,GAAE,UAAU,CAAC,kBAAkB,CAAY,EAC3D,mBAAmB,GAAE,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAW,GAChF,wBAAwB,CA6C1B"}
@@ -59,7 +59,7 @@ function selectSource(sources, size, responsivePolicy) {
59
59
  type: 'srcset',
60
60
  };
61
61
  }
62
- export default function useSourceSelection(sources, responsivePolicy = 'static', measurementCallback) {
62
+ export default function useSourceSelection(sources, responsivePolicy = 'static', measurementCallback = null) {
63
63
  const hasMoreThanOneSource = (sources?.length ?? 0) > 1;
64
64
  // null - not calculated yet, DOMRect - size available
65
65
  const [size, setSize] = useState(null);
@@ -70,7 +70,6 @@ export default function useSourceSelection(sources, responsivePolicy = 'static',
70
70
  };
71
71
  }, []);
72
72
  const containerRef = React.useCallback((element) => {
73
- // we can't short circuit here since we need to read the size for better animated transitions
74
73
  if (!hasMoreThanOneSource && !measurementCallback) {
75
74
  return;
76
75
  }
@@ -88,7 +87,7 @@ export default function useSourceSelection(sources, responsivePolicy = 'static',
88
87
  });
89
88
  resizeObserver.current.observe(element);
90
89
  }
91
- }, [hasMoreThanOneSource, responsivePolicy]);
90
+ }, [hasMoreThanOneSource, responsivePolicy, measurementCallback]);
92
91
  const source = selectSource(sources, size, responsivePolicy);
93
92
  return React.useMemo(() => ({
94
93
  containerRef,
@@ -1 +1 @@
1
- {"version":3,"file":"useSourceSelection.js","sourceRoot":"","sources":["../../src/web/useSourceSelection.ts"],"names":[],"mappings":"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","sourcesContent":["import React, { useState, useRef } from 'react';\n\nimport { ImageProps, ImageSource } from '../Image.types';\nimport { isBlurhashString, isThumbhashString } from '../utils/resolveSources';\n\nfunction findBestSourceForSize(\n sources: ImageSource[] | undefined,\n size: DOMRect | null\n): ImageSource | null {\n if (sources?.length === 1) {\n return sources[0];\n }\n return (\n [...(sources || [])]\n // look for the smallest image that's still larger then a container\n ?.map((source) => {\n if (!size) {\n return { source, penalty: 0, covers: false };\n }\n const { width, height } =\n typeof source === 'object' ? source : { width: null, height: null };\n if (width == null || height == null) {\n return { source, penalty: 0, covers: false };\n }\n if (width < size.width || height < size.height) {\n return {\n source,\n penalty: Math.max(size.width - width, size.height - height),\n covers: false,\n };\n }\n return { source, penalty: (width - size.width) * (height - size.height), covers: true };\n })\n .sort((a, b) => a.penalty - b.penalty)\n .sort((a, b) => Number(b.covers) - Number(a.covers))[0]?.source ?? null\n );\n}\n\nexport interface SrcSetSource extends ImageSource {\n srcset: string;\n sizes: string;\n // used as key and a fallback in case srcset is not supported\n uri: string;\n type: 'srcset';\n}\n\nfunction getCSSMediaQueryForSource(source: ImageSource) {\n return `(max-width: ${source.webMaxViewportWidth ?? source.width}px) ${source.width}px`;\n}\n\nfunction selectSource(\n sources: ImageSource[] | undefined,\n size: DOMRect | null,\n responsivePolicy: ImageProps['responsivePolicy']\n): ImageSource | SrcSetSource | null {\n if (sources == null || sources.length === 0) {\n return null;\n }\n\n if (sources.length === 1) {\n return sources[0];\n }\n\n if (responsivePolicy !== 'static') {\n return findBestSourceForSize(sources, size);\n }\n const staticSupportedSources = sources\n .filter(\n (s) => s.uri && s.width != null && !isBlurhashString(s.uri) && !isThumbhashString(s.uri)\n )\n .sort(\n (a, b) => (a.webMaxViewportWidth ?? a.width ?? 0) - (b.webMaxViewportWidth ?? b.width ?? 0)\n );\n\n if (staticSupportedSources.length === 0) {\n console.warn(\n \"You've set the `static` responsivePolicy but none of the sources have the `width` properties set. Make sure you set both `width` and `webMaxViewportWidth` for best results when using static responsiveness. Falling back to the `initial` policy.\"\n );\n return findBestSourceForSize(sources, size);\n }\n\n const srcset = staticSupportedSources\n ?.map((source) => `${source.uri} ${source.width}w`)\n .join(', ');\n const sizes = `${staticSupportedSources\n ?.map(getCSSMediaQueryForSource)\n .join(', ')}, ${staticSupportedSources[staticSupportedSources.length - 1]?.width}px`;\n return {\n srcset,\n sizes,\n uri: staticSupportedSources[staticSupportedSources.length - 1]?.uri ?? '',\n type: 'srcset',\n };\n}\n\ntype UseSourceSelectionReturn = {\n containerRef: (element: HTMLDivElement) => void;\n source: ImageSource | SrcSetSource | null;\n};\n\nexport default function useSourceSelection(\n sources?: ImageSource[],\n responsivePolicy: ImageProps['responsivePolicy'] = 'static',\n measurementCallback?: (target: HTMLElement, size: DOMRect) => void\n): UseSourceSelectionReturn {\n const hasMoreThanOneSource = (sources?.length ?? 0) > 1;\n // null - not calculated yet, DOMRect - size available\n const [size, setSize] = useState<null | DOMRect>(null);\n const resizeObserver = useRef<ResizeObserver | null>(null);\n\n React.useEffect(() => {\n return () => {\n resizeObserver.current?.disconnect();\n };\n }, []);\n\n const containerRef = React.useCallback(\n (element: HTMLDivElement) => {\n // we can't short circuit here since we need to read the size for better animated transitions\n if (!hasMoreThanOneSource && !measurementCallback) {\n return;\n }\n const rect = element?.getBoundingClientRect();\n measurementCallback?.(element, rect);\n setSize(rect);\n\n if (responsivePolicy === 'live') {\n resizeObserver.current?.disconnect();\n if (!element) {\n return;\n }\n resizeObserver.current = new ResizeObserver((entries) => {\n setSize(entries[0].contentRect);\n measurementCallback?.(entries[0].target as any, entries[0].contentRect);\n });\n resizeObserver.current.observe(element);\n }\n },\n [hasMoreThanOneSource, responsivePolicy]\n );\n\n const source = selectSource(sources, size, responsivePolicy);\n\n return React.useMemo(\n () => ({\n containerRef,\n source,\n }),\n [source]\n );\n}\n"]}
1
+ {"version":3,"file":"useSourceSelection.js","sourceRoot":"","sources":["../../src/web/useSourceSelection.ts"],"names":[],"mappings":"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","sourcesContent":["import React, { useState, useRef } from 'react';\n\nimport { ImageProps, ImageSource } from '../Image.types';\nimport { isBlurhashString, isThumbhashString } from '../utils/resolveSources';\n\nfunction findBestSourceForSize(\n sources: ImageSource[] | undefined,\n size: DOMRect | null\n): ImageSource | null {\n if (sources?.length === 1) {\n return sources[0];\n }\n return (\n [...(sources || [])]\n // look for the smallest image that's still larger then a container\n ?.map((source) => {\n if (!size) {\n return { source, penalty: 0, covers: false };\n }\n const { width, height } =\n typeof source === 'object' ? source : { width: null, height: null };\n if (width == null || height == null) {\n return { source, penalty: 0, covers: false };\n }\n if (width < size.width || height < size.height) {\n return {\n source,\n penalty: Math.max(size.width - width, size.height - height),\n covers: false,\n };\n }\n return { source, penalty: (width - size.width) * (height - size.height), covers: true };\n })\n .sort((a, b) => a.penalty - b.penalty)\n .sort((a, b) => Number(b.covers) - Number(a.covers))[0]?.source ?? null\n );\n}\n\nexport interface SrcSetSource extends ImageSource {\n srcset: string;\n sizes: string;\n // used as key and a fallback in case srcset is not supported\n uri: string;\n type: 'srcset';\n}\n\nfunction getCSSMediaQueryForSource(source: ImageSource) {\n return `(max-width: ${source.webMaxViewportWidth ?? source.width}px) ${source.width}px`;\n}\n\nfunction selectSource(\n sources: ImageSource[] | undefined,\n size: DOMRect | null,\n responsivePolicy: ImageProps['responsivePolicy']\n): ImageSource | SrcSetSource | null {\n if (sources == null || sources.length === 0) {\n return null;\n }\n\n if (sources.length === 1) {\n return sources[0];\n }\n\n if (responsivePolicy !== 'static') {\n return findBestSourceForSize(sources, size);\n }\n const staticSupportedSources = sources\n .filter(\n (s) => s.uri && s.width != null && !isBlurhashString(s.uri) && !isThumbhashString(s.uri)\n )\n .sort(\n (a, b) => (a.webMaxViewportWidth ?? a.width ?? 0) - (b.webMaxViewportWidth ?? b.width ?? 0)\n );\n\n if (staticSupportedSources.length === 0) {\n console.warn(\n \"You've set the `static` responsivePolicy but none of the sources have the `width` properties set. Make sure you set both `width` and `webMaxViewportWidth` for best results when using static responsiveness. Falling back to the `initial` policy.\"\n );\n return findBestSourceForSize(sources, size);\n }\n\n const srcset = staticSupportedSources\n ?.map((source) => `${source.uri} ${source.width}w`)\n .join(', ');\n const sizes = `${staticSupportedSources\n ?.map(getCSSMediaQueryForSource)\n .join(', ')}, ${staticSupportedSources[staticSupportedSources.length - 1]?.width}px`;\n return {\n srcset,\n sizes,\n uri: staticSupportedSources[staticSupportedSources.length - 1]?.uri ?? '',\n type: 'srcset',\n };\n}\n\ntype UseSourceSelectionReturn = {\n containerRef: (element: HTMLDivElement) => void;\n source: ImageSource | SrcSetSource | null;\n};\n\nexport default function useSourceSelection(\n sources?: ImageSource[],\n responsivePolicy: ImageProps['responsivePolicy'] = 'static',\n measurementCallback: ((target: HTMLElement, size: DOMRect) => void) | null = null\n): UseSourceSelectionReturn {\n const hasMoreThanOneSource = (sources?.length ?? 0) > 1;\n // null - not calculated yet, DOMRect - size available\n const [size, setSize] = useState<null | DOMRect>(null);\n const resizeObserver = useRef<ResizeObserver | null>(null);\n\n React.useEffect(() => {\n return () => {\n resizeObserver.current?.disconnect();\n };\n }, []);\n\n const containerRef = React.useCallback(\n (element: HTMLDivElement) => {\n if (!hasMoreThanOneSource && !measurementCallback) {\n return;\n }\n const rect = element?.getBoundingClientRect();\n measurementCallback?.(element, rect);\n setSize(rect);\n\n if (responsivePolicy === 'live') {\n resizeObserver.current?.disconnect();\n if (!element) {\n return;\n }\n resizeObserver.current = new ResizeObserver((entries) => {\n setSize(entries[0].contentRect);\n measurementCallback?.(entries[0].target as any, entries[0].contentRect);\n });\n resizeObserver.current.observe(element);\n }\n },\n [hasMoreThanOneSource, responsivePolicy, measurementCallback]\n );\n\n const source = selectSource(sources, size, responsivePolicy);\n\n return React.useMemo(\n () => ({\n containerRef,\n source,\n }),\n [source]\n );\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "expo-image",
3
3
  "title": "Expo Image",
4
- "version": "1.10.4",
4
+ "version": "1.10.6",
5
5
  "description": "A cross-platform, performant image component for React Native and Expo with Web support",
6
6
  "main": "build/index.js",
7
7
  "types": "build/index.d.ts",
@@ -35,5 +35,5 @@
35
35
  "peerDependencies": {
36
36
  "expo": "*"
37
37
  },
38
- "gitHead": "102899632731658eecba006c0d1c79b98ba8f5f7"
38
+ "gitHead": "4f3dcf3e23eae997f884117fdd34ad734efad9fd"
39
39
  }
@@ -63,11 +63,20 @@ function onErrorAdapter(onError?: { (event: { error: string }): void }) {
63
63
  };
64
64
  }
65
65
 
66
- // Used for some transitions to mimic native animations
67
- const setCssVariables = (element: HTMLElement, size: DOMRect) => {
66
+ // Used for flip transitions to mimic native animations
67
+ function setCssVariablesForFlipTransitions(element: HTMLElement, size: DOMRect) {
68
68
  element?.style.setProperty('--expo-image-width', `${size.width}px`);
69
69
  element?.style.setProperty('--expo-image-height', `${size.height}px`);
70
- };
70
+ }
71
+
72
+ function isFlipTransition(transition: ImageNativeProps['transition']) {
73
+ return (
74
+ transition?.effect === 'flip-from-bottom' ||
75
+ transition?.effect === 'flip-from-top' ||
76
+ transition?.effect === 'flip-from-left' ||
77
+ transition?.effect === 'flip-from-right'
78
+ );
79
+ }
71
80
 
72
81
  export default function ExpoImage({
73
82
  source,
@@ -85,6 +94,7 @@ export default function ExpoImage({
85
94
  blurRadius,
86
95
  recyclingKey,
87
96
  style,
97
+ nativeViewRef,
88
98
  ...props
89
99
  }: ImageNativeProps) {
90
100
  const imagePlaceholderContentFit = placeholderContentFit || 'scale-down';
@@ -94,7 +104,7 @@ export default function ExpoImage({
94
104
  const { containerRef, source: selectedSource } = useSourceSelection(
95
105
  source,
96
106
  responsivePolicy,
97
- setCssVariables
107
+ isFlipTransition(transition) ? setCssVariablesForFlipTransitions : null
98
108
  );
99
109
 
100
110
  const initialNodeAnimationKey =
@@ -107,6 +117,7 @@ export default function ExpoImage({
107
117
  (className, style) => (
108
118
  <ImageWrapper
109
119
  {...props}
120
+ ref={nativeViewRef as React.Ref<HTMLImageElement> | undefined}
110
121
  source={placeholder?.[0]}
111
122
  style={{
112
123
  objectFit: imagePlaceholderContentFit,
@@ -136,6 +147,7 @@ export default function ExpoImage({
136
147
  (className, style) => (
137
148
  <ImageWrapper
138
149
  {...props}
150
+ ref={nativeViewRef as React.Ref<HTMLImageElement> | undefined}
139
151
  source={selectedSource || placeholder?.[0]}
140
152
  events={{
141
153
  onError: [onErrorAdapter(onError), onLoadEnd, onErrorInner],
@@ -101,7 +101,7 @@ type UseSourceSelectionReturn = {
101
101
  export default function useSourceSelection(
102
102
  sources?: ImageSource[],
103
103
  responsivePolicy: ImageProps['responsivePolicy'] = 'static',
104
- measurementCallback?: (target: HTMLElement, size: DOMRect) => void
104
+ measurementCallback: ((target: HTMLElement, size: DOMRect) => void) | null = null
105
105
  ): UseSourceSelectionReturn {
106
106
  const hasMoreThanOneSource = (sources?.length ?? 0) > 1;
107
107
  // null - not calculated yet, DOMRect - size available
@@ -116,7 +116,6 @@ export default function useSourceSelection(
116
116
 
117
117
  const containerRef = React.useCallback(
118
118
  (element: HTMLDivElement) => {
119
- // we can't short circuit here since we need to read the size for better animated transitions
120
119
  if (!hasMoreThanOneSource && !measurementCallback) {
121
120
  return;
122
121
  }
@@ -136,7 +135,7 @@ export default function useSourceSelection(
136
135
  resizeObserver.current.observe(element);
137
136
  }
138
137
  },
139
- [hasMoreThanOneSource, responsivePolicy]
138
+ [hasMoreThanOneSource, responsivePolicy, measurementCallback]
140
139
  );
141
140
 
142
141
  const source = selectSource(sources, size, responsivePolicy);