react-native-fast-image 9.3.7 → 10.1.0
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/README.md +97 -61
- package/RNFastImage.podspec +14 -9
- package/android/build.gradle +21 -47
- package/android/consumer-rules.pro +7 -7
- package/android/src/main/AndroidManifest.xml +1 -2
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageAnimatable.java +1 -1
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageAnimated.java +2 -2
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageApng.java +2 -2
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageBlur.java +4 -6
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageCacheControl.java +1 -1
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageCacheLimits.java +4 -1
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageCacheWrite.java +1 -1
- package/android/src/main/java/com/fastimage/FastImageCrop.java +92 -0
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageEvent.java +2 -3
- package/android/src/main/java/com/fastimage/FastImageEvents.java +74 -0
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageGif.java +1 -1
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageGlide.java +13 -3
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageGlideModule.java +1 -1
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageKeyedGlideUrl.java +1 -1
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageOkHttpProgressGlideModule.java +49 -14
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageRequestListener.java +6 -1
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSharedDownloads.java +1 -1
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSource.java +12 -1
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSourceSize.java +12 -2
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSvg.java +3 -3
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSvgRenderer.java +1 -1
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageUrl.java +1 -1
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageViewConverter.java +24 -9
- package/android/src/main/java/com/fastimage/FastImageViewManager.java +591 -0
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageViewModule.java +50 -28
- package/android/src/main/java/com/fastimage/FastImageViewPackage.java +51 -0
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageViewWithUrl.java +352 -126
- package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageWebGlideUrl.java +1 -1
- package/app.plugin.js +2 -7
- package/dist/index.cjs.js +276 -157
- package/dist/index.cjs.js.flow +34 -17
- package/dist/index.cjs.web.js +211 -61
- package/dist/index.cjs.web.js.flow +34 -17
- package/dist/index.d.ts +108 -58
- package/dist/index.js +278 -159
- package/dist/index.js.flow +34 -17
- package/dist/index.web.js +212 -62
- package/dist/index.web.js.flow +34 -17
- package/dist/objectFit.d.ts +2 -2
- package/dist/objectPosition.d.ts +42 -0
- package/dist/specs/FastImageViewNativeComponent.d.ts +48 -0
- package/dist/specs/NativeFastImageModule.d.ts +11 -0
- package/dist/warnings.d.ts +3 -0
- package/ios/FastImage/FFFDownsampledImage.h +4 -8
- package/ios/FastImage/FFFDownsampledImage.m +0 -34
- package/ios/FastImage/FFFastImageModule.h +8 -0
- package/ios/FastImage/{FFFastImageViewManager.m → FFFastImageModule.mm} +89 -59
- package/ios/FastImage/FFFastImageSource.h +4 -0
- package/ios/FastImage/FFFastImageSource.m +5 -1
- package/ios/FastImage/FFFastImageView.h +36 -7
- package/ios/FastImage/FFFastImageView.m +229 -172
- package/ios/FastImage/FFFastImageViewComponentView.h +11 -0
- package/ios/FastImage/FFFastImageViewComponentView.mm +325 -0
- package/ios/FastImage/RCTConvert+FFFastImage.h +1 -1
- package/ios/FastImage/RCTConvert+FFFastImage.m +9 -10
- package/package.json +28 -9
- package/src/constants.ts +28 -0
- package/src/index.js.flow +180 -0
- package/src/index.tsx +1128 -0
- package/src/index.web.tsx +548 -0
- package/src/objectFit.ts +48 -0
- package/src/objectPosition.ts +243 -0
- package/src/specs/FastImageViewNativeComponent.ts +83 -0
- package/src/specs/NativeFastImageModule.ts +35 -0
- package/src/warnings.ts +37 -0
- package/android/src/main/AndroidManifestNew.xml +0 -3
- package/android/src/main/java/com/dylanvann/fastimage/FastImageCookieHandler.java +0 -63
- package/android/src/main/java/com/dylanvann/fastimage/FastImageEvents.java +0 -49
- package/android/src/main/java/com/dylanvann/fastimage/FastImageProgressListener.java +0 -18
- package/android/src/main/java/com/dylanvann/fastimage/FastImageShadowNode.java +0 -21
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java +0 -379
- package/android/src/main/java/com/dylanvann/fastimage/FastImageViewPackage.java +0 -27
- package/ios/FastImage/FFFastImageViewManager.h +0 -5
package/dist/index.web.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { forwardRef, memo, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
1
|
+
import React, { Children, forwardRef, memo, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
2
2
|
import { Image, PixelRatio, StyleSheet, View } from "react-native";
|
|
3
3
|
import { getAssetByID } from "react-native-web/dist/modules/AssetRegistry";
|
|
4
4
|
//#region src/constants.ts
|
|
@@ -35,13 +35,6 @@ function fromStyle(style, key) {
|
|
|
35
35
|
}
|
|
36
36
|
return style && typeof style === "object" ? style[key] : void 0;
|
|
37
37
|
}
|
|
38
|
-
const RESIZE_MODE_FIT = {
|
|
39
|
-
contain: "contain",
|
|
40
|
-
cover: "cover",
|
|
41
|
-
stretch: "fill",
|
|
42
|
-
center: "center",
|
|
43
|
-
repeat: "repeat"
|
|
44
|
-
};
|
|
45
38
|
const FITS = {
|
|
46
39
|
fill: true,
|
|
47
40
|
contain: true,
|
|
@@ -49,11 +42,202 @@ const FITS = {
|
|
|
49
42
|
none: true,
|
|
50
43
|
"scale-down": true
|
|
51
44
|
};
|
|
52
|
-
function resolveObjectFit(objectFit, style
|
|
53
|
-
var _RESIZE_MODE_FIT$resi;
|
|
45
|
+
function resolveObjectFit(objectFit, style) {
|
|
54
46
|
const fit = objectFit != null ? objectFit : fromStyle(style, "objectFit");
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
return fit && FITS[fit] === true ? fit : "cover";
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/warnings.ts
|
|
51
|
+
const warned = /* @__PURE__ */ new Set();
|
|
52
|
+
function warnOnce(key, message, level) {
|
|
53
|
+
if (!warned.has(key)) {
|
|
54
|
+
warned.add(key);
|
|
55
|
+
console[level](message);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function warnIfChildren(children) {
|
|
59
|
+
if (Children.toArray(children).length > 0) warnOnce("children", "react-native-fast-image: FastImage doesn't render children (since 10.0): use FastImageBackground for content over an image.", "error");
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/objectPosition.ts
|
|
63
|
+
const START = {
|
|
64
|
+
fraction: 0,
|
|
65
|
+
offset: 0
|
|
66
|
+
};
|
|
67
|
+
const CENTER = {
|
|
68
|
+
fraction: .5,
|
|
69
|
+
offset: 0
|
|
70
|
+
};
|
|
71
|
+
const END = {
|
|
72
|
+
fraction: 1,
|
|
73
|
+
offset: 0
|
|
74
|
+
};
|
|
75
|
+
/** The default, `50% 50%`. */
|
|
76
|
+
const CENTERED = {
|
|
77
|
+
x: CENTER,
|
|
78
|
+
y: CENTER
|
|
79
|
+
};
|
|
80
|
+
const NUMBER = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i;
|
|
81
|
+
function length(text) {
|
|
82
|
+
const lower = text.toLowerCase();
|
|
83
|
+
if (lower.endsWith("%")) {
|
|
84
|
+
const number = lower.slice(0, -1);
|
|
85
|
+
return NUMBER.test(number) ? {
|
|
86
|
+
fraction: Number(number) / 100,
|
|
87
|
+
offset: 0
|
|
88
|
+
} : null;
|
|
89
|
+
}
|
|
90
|
+
if (lower.endsWith("px")) {
|
|
91
|
+
const number = lower.slice(0, -2);
|
|
92
|
+
return NUMBER.test(number) ? {
|
|
93
|
+
fraction: 0,
|
|
94
|
+
offset: Number(number)
|
|
95
|
+
} : null;
|
|
96
|
+
}
|
|
97
|
+
return NUMBER.test(lower) && Number(lower) === 0 ? START : null;
|
|
98
|
+
}
|
|
99
|
+
function token(text) {
|
|
100
|
+
const lower = text.toLowerCase();
|
|
101
|
+
if (lower === "left" || lower === "right" || lower === "top" || lower === "bottom" || lower === "center") return { keyword: lower };
|
|
102
|
+
const axis = length(text);
|
|
103
|
+
return axis ? { length: axis } : null;
|
|
104
|
+
}
|
|
105
|
+
const X = {
|
|
106
|
+
left: START,
|
|
107
|
+
center: CENTER,
|
|
108
|
+
right: END
|
|
109
|
+
};
|
|
110
|
+
const Y = {
|
|
111
|
+
top: START,
|
|
112
|
+
center: CENTER,
|
|
113
|
+
bottom: END
|
|
114
|
+
};
|
|
115
|
+
const x = (t) => "length" in t ? t.length : X[t.keyword];
|
|
116
|
+
const y = (t) => "length" in t ? t.length : Y[t.keyword];
|
|
117
|
+
function fromEdge(edge, axis) {
|
|
118
|
+
return edge === "left" || edge === "top" ? axis : {
|
|
119
|
+
fraction: 1 - axis.fraction,
|
|
120
|
+
offset: -axis.offset || 0
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function parse(text) {
|
|
124
|
+
const tokens = [];
|
|
125
|
+
for (const part of text.trim().split(/\s+/)) {
|
|
126
|
+
const t = token(part);
|
|
127
|
+
if (!t) return null;
|
|
128
|
+
tokens.push(t);
|
|
129
|
+
}
|
|
130
|
+
if (tokens.length === 1) {
|
|
131
|
+
const [a] = tokens;
|
|
132
|
+
if ("keyword" in a && (a.keyword === "top" || a.keyword === "bottom")) return {
|
|
133
|
+
x: CENTER,
|
|
134
|
+
y: Y[a.keyword]
|
|
135
|
+
};
|
|
136
|
+
return {
|
|
137
|
+
x: x(a),
|
|
138
|
+
y: CENTER
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
if (tokens.length === 2) {
|
|
142
|
+
const [a, b] = tokens;
|
|
143
|
+
const ax = x(a);
|
|
144
|
+
const by = y(b);
|
|
145
|
+
if (ax && by) return {
|
|
146
|
+
x: ax,
|
|
147
|
+
y: by
|
|
148
|
+
};
|
|
149
|
+
if ("keyword" in a && "keyword" in b) {
|
|
150
|
+
const bx = X[b.keyword];
|
|
151
|
+
const ay = Y[a.keyword];
|
|
152
|
+
if (bx && ay) return {
|
|
153
|
+
x: bx,
|
|
154
|
+
y: ay
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
if (tokens.length === 4) {
|
|
160
|
+
const [a, b, c, d] = tokens;
|
|
161
|
+
if (!("keyword" in a && "length" in b && "keyword" in c && "length" in d)) return null;
|
|
162
|
+
const horizontal = (k) => k === "left" || k === "right";
|
|
163
|
+
const vertical = (k) => k === "top" || k === "bottom";
|
|
164
|
+
if (horizontal(a.keyword) && vertical(c.keyword)) return {
|
|
165
|
+
x: fromEdge(a.keyword, b.length),
|
|
166
|
+
y: fromEdge(c.keyword, d.length)
|
|
167
|
+
};
|
|
168
|
+
if (vertical(a.keyword) && horizontal(c.keyword)) return {
|
|
169
|
+
x: fromEdge(c.keyword, d.length),
|
|
170
|
+
y: fromEdge(a.keyword, b.length)
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
const parsed = /* @__PURE__ */ new Map();
|
|
176
|
+
function objectLength(value) {
|
|
177
|
+
if (typeof value === "number") return Number.isFinite(value) ? {
|
|
178
|
+
fraction: 0,
|
|
179
|
+
offset: value
|
|
180
|
+
} : null;
|
|
181
|
+
return typeof value === "string" && value.endsWith("%") ? length(value) : null;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* The position for objectPosition, or null if it isn't valid. A string is
|
|
185
|
+
* CSS's syntax; an object has one of `top` and `bottom` and one of `left`
|
|
186
|
+
* and `right`, each in points or a percentage, and a missing axis is
|
|
187
|
+
* centered. Unset is centered.
|
|
188
|
+
*/
|
|
189
|
+
function resolveObjectPosition(position) {
|
|
190
|
+
if (position == null) return CENTERED;
|
|
191
|
+
if (typeof position === "string") {
|
|
192
|
+
let result = parsed.get(position);
|
|
193
|
+
if (result === void 0) {
|
|
194
|
+
result = parse(position);
|
|
195
|
+
if (parsed.size < 100) parsed.set(position, result);
|
|
196
|
+
}
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
if (typeof position !== "object") return null;
|
|
200
|
+
const edges = position;
|
|
201
|
+
const axis = (start, end) => {
|
|
202
|
+
const hasStart = edges[start] != null;
|
|
203
|
+
const hasEnd = edges[end] != null;
|
|
204
|
+
if (hasStart && hasEnd) return null;
|
|
205
|
+
if (!hasStart && !hasEnd) return CENTER;
|
|
206
|
+
const edge = hasStart ? start : end;
|
|
207
|
+
const value = objectLength(edges[edge]);
|
|
208
|
+
return value && fromEdge(edge, value);
|
|
209
|
+
};
|
|
210
|
+
const resolvedX = axis("left", "right");
|
|
211
|
+
const resolvedY = axis("top", "bottom");
|
|
212
|
+
return resolvedX && resolvedY ? {
|
|
213
|
+
x: resolvedX,
|
|
214
|
+
y: resolvedY
|
|
215
|
+
} : null;
|
|
216
|
+
}
|
|
217
|
+
const round = (n) => Math.round(n * 1e6) / 1e6;
|
|
218
|
+
/**
|
|
219
|
+
* The position for objectPosition, or centered if it isn't valid (as CSS
|
|
220
|
+
* ignores it), with a warning in development.
|
|
221
|
+
*/
|
|
222
|
+
function objectPositionOrCentered(position) {
|
|
223
|
+
const resolved = resolveObjectPosition(position);
|
|
224
|
+
if (resolved) return resolved;
|
|
225
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
226
|
+
const value = JSON.stringify(position);
|
|
227
|
+
warnOnce(`objectPosition ${value}`, `react-native-fast-image: objectPosition ${value} isn't a position, so the image is centered. Use CSS's syntax with px or % (e.g. 'right 10px bottom 20%'), or { top | bottom, left | right } in points or percentages.`, "warn");
|
|
228
|
+
}
|
|
229
|
+
return CENTERED;
|
|
230
|
+
}
|
|
231
|
+
/** The position as CSS (for the web version's object-position). */
|
|
232
|
+
function cssPosition({ x, y }) {
|
|
233
|
+
const axis = ({ fraction, offset }) => {
|
|
234
|
+
const percent = round(fraction * 100);
|
|
235
|
+
const px = round(offset);
|
|
236
|
+
if (px === 0) return `${percent}%`;
|
|
237
|
+
if (percent === 0) return `${px}px`;
|
|
238
|
+
return `calc(${percent}% ${px < 0 ? "-" : "+"} ${Math.abs(px)}px)`;
|
|
239
|
+
};
|
|
240
|
+
return `${axis(x)} ${axis(y)}`;
|
|
57
241
|
}
|
|
58
242
|
//#endregion
|
|
59
243
|
//#region src/index.web.tsx
|
|
@@ -66,8 +250,9 @@ let ids = 0;
|
|
|
66
250
|
const useCounterId = () => useState(() => `${++ids}`)[0];
|
|
67
251
|
const useSvgId = (_useId = React.useId) !== null && _useId !== void 0 ? _useId : useCounterId;
|
|
68
252
|
const useClientLayoutEffect = globalThis.document === void 0 ? useEffect : useLayoutEffect;
|
|
69
|
-
function FastImageBase({ source, defaultSource, tintColor, blurRadius, onLoadStart, onLoad, onError, onLoadEnd, style, children, objectFit,
|
|
70
|
-
|
|
253
|
+
function FastImageBase({ source, defaultSource, tintColor, blurRadius, onLoadStart, onLoad, onError, onLoadEnd, style, children, objectFit, objectPosition, forwardedRef, onLayout, pointerEvents, recyclingKey: _recyclingKey, loop: _loop, imageRendering: _imageRendering, paused: _paused, transition: _transition, downsample: _downsample, onProgress: _onProgress, ...props }) {
|
|
254
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) warnIfChildren(children);
|
|
255
|
+
const { accessibilityLabel, "aria-label": ariaLabel, resizeMode: _resizeMode, ...viewProps } = props;
|
|
71
256
|
const label = ariaLabel || accessibilityLabel || void 0;
|
|
72
257
|
const several = Array.isArray(source) && source.length > 1 ? source : void 0;
|
|
73
258
|
const sized = several ? sizedSources(several) : void 0;
|
|
@@ -78,8 +263,8 @@ function FastImageBase({ source, defaultSource, tintColor, blurRadius, onLoadSta
|
|
|
78
263
|
const [result, setResult] = useState();
|
|
79
264
|
const ok = result && result.key === key ? result.ok : void 0;
|
|
80
265
|
const tintId = `fast-image-tint-${useSvgId().replace(/[^\w-]/g, "")}`;
|
|
81
|
-
const
|
|
82
|
-
const
|
|
266
|
+
const fit = resolveObjectFit(objectFit, style);
|
|
267
|
+
const position = cssPosition(objectPositionOrCentered(objectPosition));
|
|
83
268
|
const filter = [blurRadius ? `blur(${blurRadius}px)` : "", tintColor ? `url(#${tintId})` : ""].filter(Boolean).join(" ") || void 0;
|
|
84
269
|
const showDefault = !!defaultUri && ok !== true;
|
|
85
270
|
useClientLayoutEffect(() => {
|
|
@@ -96,6 +281,7 @@ function FastImageBase({ source, defaultSource, tintColor, blurRadius, onLoadSta
|
|
|
96
281
|
key: `default ${defaultUri}`,
|
|
97
282
|
src: defaultUri,
|
|
98
283
|
fit,
|
|
284
|
+
position,
|
|
99
285
|
filter,
|
|
100
286
|
alt: key ? "" : label !== null && label !== void 0 ? label : ""
|
|
101
287
|
}) : null, key && src ? /* @__PURE__ */ React.createElement(Picture, {
|
|
@@ -104,6 +290,7 @@ function FastImageBase({ source, defaultSource, tintColor, blurRadius, onLoadSta
|
|
|
104
290
|
srcSet,
|
|
105
291
|
lazy: !!several,
|
|
106
292
|
fit,
|
|
293
|
+
position,
|
|
107
294
|
filter,
|
|
108
295
|
hidden: ok === false,
|
|
109
296
|
alt: label !== null && label !== void 0 ? label : "",
|
|
@@ -138,7 +325,7 @@ function FastImageBase({ source, defaultSource, tintColor, blurRadius, onLoadSta
|
|
|
138
325
|
}) : null, tintColor ? /* @__PURE__ */ React.createElement(TintFilter, {
|
|
139
326
|
id: tintId,
|
|
140
327
|
color: tintColor
|
|
141
|
-
}) : null
|
|
328
|
+
}) : null);
|
|
142
329
|
}
|
|
143
330
|
function resolveUri(source) {
|
|
144
331
|
let uri;
|
|
@@ -186,14 +373,10 @@ const fill = {
|
|
|
186
373
|
width: "100%",
|
|
187
374
|
height: "100%"
|
|
188
375
|
};
|
|
189
|
-
function Picture({ src, srcSet, lazy, fit, filter, hidden, alt, onLoad, onError }) {
|
|
190
|
-
const repeat = fit === "repeat";
|
|
376
|
+
function Picture({ src, srcSet, lazy, fit, position, filter, hidden, alt, onLoad, onError }) {
|
|
191
377
|
const image = useRef(null);
|
|
192
|
-
const tiles = useRef(null);
|
|
193
378
|
const mounted = useRef(true);
|
|
194
379
|
const handled = useRef(void 0);
|
|
195
|
-
const [natural, setNatural] = useState();
|
|
196
|
-
const [box, setBox] = useState();
|
|
197
380
|
const loaded = (target) => {
|
|
198
381
|
var _handled$current, _target$decode;
|
|
199
382
|
const file = target.currentSrc || src;
|
|
@@ -203,10 +386,6 @@ function Picture({ src, srcSet, lazy, fit, filter, hidden, alt, onLoad, onError
|
|
|
203
386
|
sources,
|
|
204
387
|
file
|
|
205
388
|
};
|
|
206
|
-
setNatural({
|
|
207
|
-
width: target.naturalWidth,
|
|
208
|
-
height: target.naturalHeight
|
|
209
|
-
});
|
|
210
389
|
const done = () => {
|
|
211
390
|
if (mounted.current) onLoad === null || onLoad === void 0 || onLoad(target);
|
|
212
391
|
};
|
|
@@ -227,21 +406,7 @@ function Picture({ src, srcSet, lazy, fit, filter, hidden, alt, onLoad, onError
|
|
|
227
406
|
if (mounted.current) onError === null || onError === void 0 || onError(target.currentSrc || src);
|
|
228
407
|
});
|
|
229
408
|
}, []);
|
|
230
|
-
|
|
231
|
-
const Observer = globalThis.ResizeObserver;
|
|
232
|
-
const node = tiles.current;
|
|
233
|
-
if (!repeat || !node || !Observer) return;
|
|
234
|
-
const observer = new Observer((entries) => {
|
|
235
|
-
const { width, height } = entries[0].contentRect;
|
|
236
|
-
setBox({
|
|
237
|
-
width,
|
|
238
|
-
height
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
|
-
observer.observe(node);
|
|
242
|
-
return () => observer.disconnect();
|
|
243
|
-
}, [repeat]);
|
|
244
|
-
const img = /* @__PURE__ */ React.createElement("img", {
|
|
409
|
+
return /* @__PURE__ */ React.createElement("img", {
|
|
245
410
|
ref: image,
|
|
246
411
|
src,
|
|
247
412
|
srcSet,
|
|
@@ -251,9 +416,10 @@ function Picture({ src, srcSet, lazy, fit, filter, hidden, alt, onLoad, onError
|
|
|
251
416
|
draggable: false,
|
|
252
417
|
style: {
|
|
253
418
|
...fill,
|
|
254
|
-
objectFit:
|
|
255
|
-
|
|
256
|
-
|
|
419
|
+
objectFit: fit,
|
|
420
|
+
objectPosition: position,
|
|
421
|
+
filter,
|
|
422
|
+
opacity: hidden ? 0 : void 0
|
|
257
423
|
},
|
|
258
424
|
onLoad: (event) => loaded(event.currentTarget),
|
|
259
425
|
onError: (event) => {
|
|
@@ -261,23 +427,6 @@ function Picture({ src, srcSet, lazy, fit, filter, hidden, alt, onLoad, onError
|
|
|
261
427
|
if (mounted.current) onError === null || onError === void 0 || onError((target === null || target === void 0 ? void 0 : target.currentSrc) || src);
|
|
262
428
|
}
|
|
263
429
|
});
|
|
264
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, repeat ? /* @__PURE__ */ React.createElement("div", {
|
|
265
|
-
ref: tiles,
|
|
266
|
-
style: {
|
|
267
|
-
...fill,
|
|
268
|
-
backgroundImage: `url("${src}")`,
|
|
269
|
-
backgroundRepeat: "repeat",
|
|
270
|
-
backgroundPosition: "0",
|
|
271
|
-
backgroundSize: tileSize(natural, box),
|
|
272
|
-
filter,
|
|
273
|
-
opacity: hidden ? 0 : void 0
|
|
274
|
-
}
|
|
275
|
-
}) : null, img);
|
|
276
|
-
}
|
|
277
|
-
function tileSize(natural, box) {
|
|
278
|
-
if (!(natural === null || natural === void 0 ? void 0 : natural.width) || !natural.height || !(box === null || box === void 0 ? void 0 : box.width) || !box.height) return;
|
|
279
|
-
const scale = Math.min(1, box.width / natural.width, box.height / natural.height);
|
|
280
|
-
return `${Math.ceil(scale * natural.width)}px ${Math.ceil(scale * natural.height)}px`;
|
|
281
430
|
}
|
|
282
431
|
function TintFilter({ id, color }) {
|
|
283
432
|
return /* @__PURE__ */ React.createElement("svg", { style: tintStyle }, /* @__PURE__ */ React.createElement("defs", null, /* @__PURE__ */ React.createElement("filter", { id }, /* @__PURE__ */ React.createElement("feFlood", {
|
|
@@ -312,9 +461,9 @@ function getSize(uri) {
|
|
|
312
461
|
});
|
|
313
462
|
}
|
|
314
463
|
const FastImage = FastImageComponent;
|
|
315
|
-
FastImage.resizeMode = resizeMode;
|
|
316
464
|
FastImage.cacheControl = cacheControl;
|
|
317
465
|
FastImage.priority = priority;
|
|
466
|
+
FastImage.resizeMode = resizeMode;
|
|
318
467
|
FastImage.preload = (sources) => Promise.all(sources.map((source) => {
|
|
319
468
|
const uri = source ? source.uri : void 0;
|
|
320
469
|
if (typeof uri !== "string" || !uri) return Promise.resolve({
|
|
@@ -335,6 +484,7 @@ FastImage.preload = (sources) => Promise.all(sources.map((source) => {
|
|
|
335
484
|
FastImage.clearMemoryCache = () => Promise.resolve(notSupported);
|
|
336
485
|
FastImage.clearDiskCache = () => Promise.resolve(notSupported);
|
|
337
486
|
FastImage.configureCache = () => Promise.resolve({});
|
|
487
|
+
FastImage.setDefaults = () => {};
|
|
338
488
|
FastImage.writeToCache = () => Promise.resolve(notSupported);
|
|
339
489
|
FastImage.getCachePath = () => Promise.resolve(notSupported);
|
|
340
490
|
const styles = StyleSheet.create({ container: { overflow: "hidden" } });
|
package/dist/index.web.js.flow
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
|
|
3
|
-
import type { ViewProps } from 'react-native
|
|
4
|
-
import type { SyntheticEvent } from 'react-native/Libraries/Types/CoreEventTypes'
|
|
3
|
+
import type { NativeSyntheticEvent, ViewProps } from 'react-native'
|
|
5
4
|
|
|
6
|
-
export type OnLoadEvent =
|
|
5
|
+
export type OnLoadEvent = NativeSyntheticEvent<
|
|
7
6
|
$ReadOnly<{
|
|
8
7
|
width: number,
|
|
9
8
|
height: number,
|
|
10
|
-
// The view's React tag
|
|
11
|
-
// TODO: make it required once the New Architecture is the minimum.
|
|
9
|
+
// The view's React tag (on iOS and Android; not on the web).
|
|
12
10
|
target?: number,
|
|
13
11
|
}>,
|
|
14
12
|
>
|
|
15
13
|
|
|
16
|
-
export type OnErrorEvent =
|
|
14
|
+
export type OnErrorEvent = NativeSyntheticEvent<
|
|
17
15
|
$ReadOnly<{|
|
|
18
16
|
error: string,
|
|
19
17
|
|}>,
|
|
20
18
|
>
|
|
21
19
|
|
|
22
|
-
export type OnProgressEvent =
|
|
20
|
+
export type OnProgressEvent = NativeSyntheticEvent<
|
|
23
21
|
$ReadOnly<{|
|
|
24
22
|
loaded: number,
|
|
25
23
|
total: number,
|
|
@@ -28,6 +26,12 @@ export type OnProgressEvent = SyntheticEvent<
|
|
|
28
26
|
|}>,
|
|
29
27
|
>
|
|
30
28
|
|
|
29
|
+
export type Priority = $ReadOnly<{|
|
|
30
|
+
low: 'low',
|
|
31
|
+
normal: 'normal',
|
|
32
|
+
high: 'high',
|
|
33
|
+
|}>
|
|
34
|
+
|
|
31
35
|
export type ResizeMode = $ReadOnly<{|
|
|
32
36
|
contain: 'contain',
|
|
33
37
|
cover: 'cover',
|
|
@@ -36,20 +40,22 @@ export type ResizeMode = $ReadOnly<{|
|
|
|
36
40
|
repeat: 'repeat',
|
|
37
41
|
|}>
|
|
38
42
|
|
|
39
|
-
export type Priority = $ReadOnly<{|
|
|
40
|
-
low: 'low',
|
|
41
|
-
normal: 'normal',
|
|
42
|
-
high: 'high',
|
|
43
|
-
|}>
|
|
44
|
-
|
|
45
43
|
export type CacheControl = $ReadOnly<{|
|
|
46
44
|
immutable: 'immutable',
|
|
47
45
|
web: 'web',
|
|
48
46
|
cacheOnly: 'cacheOnly',
|
|
49
47
|
|}>
|
|
50
48
|
|
|
51
|
-
export type ResizeModes = $Values<ResizeMode>
|
|
52
49
|
export type ObjectFit = 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'
|
|
50
|
+
export type PositionLength = number | string
|
|
51
|
+
export type ObjectPosition =
|
|
52
|
+
| string
|
|
53
|
+
| $ReadOnly<{|
|
|
54
|
+
top?: PositionLength,
|
|
55
|
+
bottom?: PositionLength,
|
|
56
|
+
left?: PositionLength,
|
|
57
|
+
right?: PositionLength,
|
|
58
|
+
|}>
|
|
53
59
|
export type Priorities = $Values<Priority>
|
|
54
60
|
export type CacheControls = $Values<CacheControl>
|
|
55
61
|
|
|
@@ -82,6 +88,10 @@ export type Transition = $ReadOnly<{|
|
|
|
82
88
|
skipOnCacheHit?: ?('none' | 'memory' | 'all'),
|
|
83
89
|
|}>
|
|
84
90
|
|
|
91
|
+
export type FastImageDefaults = $ReadOnly<{|
|
|
92
|
+
transition?: ?(boolean | number | Transition),
|
|
93
|
+
|}>
|
|
94
|
+
|
|
85
95
|
export type PreloadSuccess = {|
|
|
86
96
|
uri: string,
|
|
87
97
|
ok: true,
|
|
@@ -107,6 +117,7 @@ export type FastImageSource = {
|
|
|
107
117
|
cache?: CacheControls,
|
|
108
118
|
cacheKey?: string,
|
|
109
119
|
memoryCache?: boolean,
|
|
120
|
+
diskCache?: boolean,
|
|
110
121
|
width?: number,
|
|
111
122
|
height?: number,
|
|
112
123
|
scale?: number,
|
|
@@ -125,9 +136,7 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
125
136
|
|
|
126
137
|
tintColor?: number | string,
|
|
127
138
|
objectFit?: ?ObjectFit,
|
|
128
|
-
|
|
129
|
-
resizeMode?: ?ResizeModes,
|
|
130
|
-
fallback?: ?boolean,
|
|
139
|
+
objectPosition?: ?ObjectPosition,
|
|
131
140
|
recyclingKey?: ?string,
|
|
132
141
|
loop?: ?(boolean | number),
|
|
133
142
|
imageRendering?: ?('auto' | 'smooth' | 'pixelated'),
|
|
@@ -136,6 +145,9 @@ export type FastImageProps = $ReadOnly<{|
|
|
|
136
145
|
downsample?: ?boolean,
|
|
137
146
|
blurRadius?: ?number,
|
|
138
147
|
testID?: ?string,
|
|
148
|
+
// FastImage is a single native view, which doesn't take children (since
|
|
149
|
+
// 10.0): use FastImageBackground.
|
|
150
|
+
children?: "FastImage doesn't take children: use FastImageBackground for content over an image",
|
|
139
151
|
|}>
|
|
140
152
|
|
|
141
153
|
export type FastImageBackgroundProps = $ReadOnly<{|
|
|
@@ -148,14 +160,19 @@ export type FastImageBackgroundProps = $ReadOnly<{|
|
|
|
148
160
|
declare export var FastImageBackground: React$ComponentType<FastImageBackgroundProps>
|
|
149
161
|
|
|
150
162
|
declare export default class FastImage extends React$Component<FastImageProps> {
|
|
163
|
+
// Deprecated: removed in 10.0, and a resizeMode prop is ignored; use
|
|
164
|
+
// objectFit. Kept so code that reads it doesn't throw.
|
|
151
165
|
static resizeMode: ResizeMode;
|
|
166
|
+
// Deprecated: use the strings instead, e.g. priority: 'high'.
|
|
152
167
|
static priority: Priority;
|
|
168
|
+
// Deprecated: use the strings instead, e.g. cache: 'immutable'.
|
|
153
169
|
static cacheControl: CacheControl;
|
|
154
170
|
static preload: PreloadFn;
|
|
155
171
|
static clearMemoryCache: () => Promise<ClearCacheResult>;
|
|
156
172
|
static clearDiskCache: () => Promise<ClearCacheResult>;
|
|
157
173
|
static getCachePath: (source: FastImageSource) => Promise<CachePathResult>;
|
|
158
174
|
static configureCache: (limits?: CacheLimits) => Promise<CacheState>;
|
|
175
|
+
static setDefaults: (defaults: FastImageDefaults) => void;
|
|
159
176
|
static writeToCache: (
|
|
160
177
|
source: FastImageSource,
|
|
161
178
|
file: string,
|
package/dist/objectFit.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { ImageStyle, ObjectFit
|
|
1
|
+
import type { ImageStyle, ObjectFit } from './index';
|
|
2
2
|
export declare function fromStyle<K extends 'tintColor' | 'objectFit'>(style: unknown, key: K): ImageStyle[K];
|
|
3
|
-
export declare function resolveObjectFit(objectFit: ObjectFit | null | undefined, style: unknown
|
|
3
|
+
export declare function resolveObjectFit(objectFit: ObjectFit | null | undefined, style: unknown): ObjectFit;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** A length in points (dp on Android), or a percentage: see [`objectPosition`](#objectposition). */
|
|
2
|
+
export type PositionLength = number | `${number}%`;
|
|
3
|
+
/**
|
|
4
|
+
* Where the image is in the view: see [`objectPosition`](#objectposition).
|
|
5
|
+
*/
|
|
6
|
+
export type ObjectPosition = string | (({
|
|
7
|
+
top?: PositionLength;
|
|
8
|
+
bottom?: never;
|
|
9
|
+
} | {
|
|
10
|
+
bottom: PositionLength;
|
|
11
|
+
top?: never;
|
|
12
|
+
}) & ({
|
|
13
|
+
left?: PositionLength;
|
|
14
|
+
right?: never;
|
|
15
|
+
} | {
|
|
16
|
+
right: PositionLength;
|
|
17
|
+
left?: never;
|
|
18
|
+
}));
|
|
19
|
+
export type ResolvedAxis = {
|
|
20
|
+
fraction: number;
|
|
21
|
+
offset: number;
|
|
22
|
+
};
|
|
23
|
+
export type ResolvedPosition = {
|
|
24
|
+
x: ResolvedAxis;
|
|
25
|
+
y: ResolvedAxis;
|
|
26
|
+
};
|
|
27
|
+
/** The default, `50% 50%`. */
|
|
28
|
+
export declare const CENTERED: ResolvedPosition;
|
|
29
|
+
/**
|
|
30
|
+
* The position for objectPosition, or null if it isn't valid. A string is
|
|
31
|
+
* CSS's syntax; an object has one of `top` and `bottom` and one of `left`
|
|
32
|
+
* and `right`, each in points or a percentage, and a missing axis is
|
|
33
|
+
* centered. Unset is centered.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveObjectPosition(position: ObjectPosition | null | undefined): ResolvedPosition | null;
|
|
36
|
+
/**
|
|
37
|
+
* The position for objectPosition, or centered if it isn't valid (as CSS
|
|
38
|
+
* ignores it), with a warning in development.
|
|
39
|
+
*/
|
|
40
|
+
export declare function objectPositionOrCentered(position: ObjectPosition | null | undefined): ResolvedPosition;
|
|
41
|
+
/** The position as CSS (for the web version's object-position). */
|
|
42
|
+
export declare function cssPosition({ x, y }: ResolvedPosition): string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { CodegenTypes, ColorValue, HostComponent, ViewProps } from 'react-native';
|
|
2
|
+
type LoadStartEvent = Readonly<{}>;
|
|
3
|
+
type ProgressEvent = Readonly<{
|
|
4
|
+
loaded: CodegenTypes.Double;
|
|
5
|
+
total: CodegenTypes.Double;
|
|
6
|
+
progress: CodegenTypes.Double;
|
|
7
|
+
}>;
|
|
8
|
+
type LoadEvent = Readonly<{
|
|
9
|
+
width: CodegenTypes.Double;
|
|
10
|
+
height: CodegenTypes.Double;
|
|
11
|
+
}>;
|
|
12
|
+
type ErrorEvent = Readonly<{
|
|
13
|
+
error: string;
|
|
14
|
+
}>;
|
|
15
|
+
type LoadEndEvent = Readonly<{
|
|
16
|
+
ok: boolean;
|
|
17
|
+
width?: CodegenTypes.Double;
|
|
18
|
+
height?: CodegenTypes.Double;
|
|
19
|
+
error?: string;
|
|
20
|
+
}>;
|
|
21
|
+
export interface NativeProps extends ViewProps {
|
|
22
|
+
source?: CodegenTypes.UnsafeMixed;
|
|
23
|
+
sources?: CodegenTypes.UnsafeMixed;
|
|
24
|
+
defaultSource?: CodegenTypes.UnsafeMixed;
|
|
25
|
+
objectFit?: CodegenTypes.WithDefault<string, 'cover'>;
|
|
26
|
+
objectPositionX?: CodegenTypes.WithDefault<CodegenTypes.Float, 0.5>;
|
|
27
|
+
objectPositionXOffset?: CodegenTypes.Float;
|
|
28
|
+
objectPositionY?: CodegenTypes.WithDefault<CodegenTypes.Float, 0.5>;
|
|
29
|
+
objectPositionYOffset?: CodegenTypes.Float;
|
|
30
|
+
tintColor?: ColorValue;
|
|
31
|
+
recyclingKey?: string;
|
|
32
|
+
loopCount?: CodegenTypes.WithDefault<CodegenTypes.Int32, -1>;
|
|
33
|
+
imageRendering?: string;
|
|
34
|
+
paused?: boolean;
|
|
35
|
+
transitionDuration?: CodegenTypes.Double;
|
|
36
|
+
transitionBetweenImages?: boolean;
|
|
37
|
+
transitionSkipOnCacheHit?: string;
|
|
38
|
+
downsample?: CodegenTypes.WithDefault<boolean, true>;
|
|
39
|
+
blurRadius?: CodegenTypes.Float;
|
|
40
|
+
handledEvents?: CodegenTypes.Int32;
|
|
41
|
+
onFastImageLoadStart?: CodegenTypes.DirectEventHandler<LoadStartEvent>;
|
|
42
|
+
onFastImageProgress?: CodegenTypes.DirectEventHandler<ProgressEvent>;
|
|
43
|
+
onFastImageLoad?: CodegenTypes.DirectEventHandler<LoadEvent>;
|
|
44
|
+
onFastImageError?: CodegenTypes.DirectEventHandler<ErrorEvent>;
|
|
45
|
+
onFastImageLoadEnd?: CodegenTypes.DirectEventHandler<LoadEndEvent>;
|
|
46
|
+
}
|
|
47
|
+
declare const _default: HostComponent<NativeProps>;
|
|
48
|
+
export default _default;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CodegenTypes, TurboModule } from 'react-native';
|
|
2
|
+
export interface Spec extends TurboModule {
|
|
3
|
+
preload(sources: Array<CodegenTypes.UnsafeObject>): Promise<Array<CodegenTypes.UnsafeObject>>;
|
|
4
|
+
getCachePath(source: CodegenTypes.UnsafeObject): Promise<CodegenTypes.UnsafeObject>;
|
|
5
|
+
writeToCache(source: CodegenTypes.UnsafeObject, file: string): Promise<CodegenTypes.UnsafeObject>;
|
|
6
|
+
configureCache(limits: CodegenTypes.UnsafeObject): Promise<CodegenTypes.UnsafeObject>;
|
|
7
|
+
clearMemoryCache(): Promise<CodegenTypes.UnsafeObject>;
|
|
8
|
+
clearDiskCache(): Promise<CodegenTypes.UnsafeObject>;
|
|
9
|
+
}
|
|
10
|
+
declare const _default: Spec | null;
|
|
11
|
+
export default _default;
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
// An image decoded at about the size it's shown at (the `downsample`
|
|
5
5
|
// prop), instead of at full size. The view asks for it with SDWebImage's
|
|
6
6
|
// thumbnail context: the box to fill (the view's size in pixels), and
|
|
7
|
-
// preserveAspectRatio NO when the image has to cover the box (
|
|
8
|
-
// cover or
|
|
7
|
+
// preserveAspectRatio NO when the image has to cover the box (objectFit
|
|
8
|
+
// cover or fill) rather than fit in it (contain or scale-down). SDWebImage's
|
|
9
9
|
// own thumbnail decoding can only fit, so this class works out the size from
|
|
10
10
|
// the image's header before it decodes, as React Native's Image does.
|
|
11
11
|
@interface FFFDownsampledImage : SDAnimatedImage
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
// or fit in.
|
|
15
15
|
+ (void) addToContext: (SDWebImageMutableContext*)context box: (CGSize)box cover: (BOOL)cover;
|
|
16
16
|
|
|
17
|
-
// Sets a load's context to decode the image at full size, through this class
|
|
18
|
-
//
|
|
17
|
+
// Sets a load's context to decode the image at full size, through this class.
|
|
18
|
+
// Every FastImage load uses it, so loads of the same url
|
|
19
19
|
// can share a download: SDWebImage's downloader decodes each load of a
|
|
20
20
|
// download with the first load's image class (and each with its own size),
|
|
21
21
|
// and SDWebImage's own thumbnail decoding can't cover a box.
|
|
@@ -33,8 +33,4 @@
|
|
|
33
33
|
// decodes the file from the disk cache. Call it before a full-size load.
|
|
34
34
|
+ (void) forgetSmallerFullSizeImageForURL: (NSURL*)url context: (SDWebImageContext*)context;
|
|
35
35
|
|
|
36
|
-
// Whether this version of SDWebImage can decode through this class: it
|
|
37
|
-
// decodes static images through the animated image class since 5.19.
|
|
38
|
-
+ (BOOL) isSupported;
|
|
39
|
-
|
|
40
36
|
@end
|