react-native-fast-image 8.22.0 → 8.23.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 +10 -0
- package/dist/constants.d.ts +16 -0
- package/dist/index.cjs.js +3 -1
- package/dist/index.cjs.web.js +193 -0
- package/dist/index.cjs.web.js.flow +154 -0
- package/dist/index.d.ts +1 -16
- package/dist/index.js +3 -1
- package/dist/index.web.d.ts +6 -0
- package/dist/index.web.js +165 -0
- package/dist/index.web.js.flow +154 -0
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -486,6 +486,16 @@ On Android, if your app has its own `AppGlideModule` (see [Are you using Glide a
|
|
|
486
486
|
|
|
487
487
|
Images with `cache: 'web'` are kept in their own HTTP cache instead, up to 50 MB on each platform, which these limits don't change.
|
|
488
488
|
|
|
489
|
+
## Web
|
|
490
|
+
|
|
491
|
+
With [react-native-web](https://necolas.github.io/react-native-web/), FastImage shows images with the web's `Image`. Bundlers pick the web version through the package's `browser` field, or the `.web.js` files next to the native ones.
|
|
492
|
+
|
|
493
|
+
Support is minimal:
|
|
494
|
+
|
|
495
|
+
- Props that work: `source` (a `uri`, or a `require()`d image), `defaultSource`, `resizeMode`, `tintColor`, `blurRadius`, `style`, children, `onLoadStart`, `onLoad`, `onError`, `onLoadEnd`, and View props such as `testID`, accessibility props, `onLayout` and `pointerEvents`.
|
|
496
|
+
- Ignored: `source.headers` (a browser can't send them for an image), `source.priority`, `source.cache`, `source.cacheKey`, `source.memoryCache`, `recyclingKey`, `loop`, `imageRendering`, `paused`, `transition`, `downsample`, `fallback` and `onProgress`.
|
|
497
|
+
- `FastImage.preload` loads the images into the browser's cache and resolves with a result per source. `clearMemoryCache`, `clearDiskCache` and `configureCache` resolve without doing anything (the browser manages its cache), and `getCachePath` and `writeToCache` resolve with `{ ok: false, error: 'Not supported on the web' }`.
|
|
498
|
+
|
|
489
499
|
## Troubleshooting
|
|
490
500
|
|
|
491
501
|
If you have any problems using this library try the steps in [troubleshooting](docs/troubleshooting.md) and see if they fix it.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const resizeMode: {
|
|
2
|
+
readonly contain: 'contain';
|
|
3
|
+
readonly cover: 'cover';
|
|
4
|
+
readonly stretch: 'stretch';
|
|
5
|
+
readonly center: 'center';
|
|
6
|
+
};
|
|
7
|
+
export declare const priority: {
|
|
8
|
+
readonly low: 'low';
|
|
9
|
+
readonly normal: 'normal';
|
|
10
|
+
readonly high: 'high';
|
|
11
|
+
};
|
|
12
|
+
export declare const cacheControl: {
|
|
13
|
+
readonly immutable: 'immutable';
|
|
14
|
+
readonly web: 'web';
|
|
15
|
+
readonly cacheOnly: 'cacheOnly';
|
|
16
|
+
};
|
package/dist/index.cjs.js
CHANGED
|
@@ -27,7 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
let react = require("react");
|
|
28
28
|
react = __toESM(react);
|
|
29
29
|
let react_native = require("react-native");
|
|
30
|
-
//#region src/
|
|
30
|
+
//#region src/constants.ts
|
|
31
31
|
const resizeMode = {
|
|
32
32
|
contain: "contain",
|
|
33
33
|
cover: "cover",
|
|
@@ -44,6 +44,8 @@ const cacheControl = {
|
|
|
44
44
|
web: "web",
|
|
45
45
|
cacheOnly: "cacheOnly"
|
|
46
46
|
};
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/index.tsx
|
|
47
49
|
const resolveDefaultSource = (defaultSource) => {
|
|
48
50
|
if (!defaultSource) return null;
|
|
49
51
|
if (react_native.Platform.OS === "android") {
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
Object.defineProperties(exports, {
|
|
2
|
+
__esModule: { value: true },
|
|
3
|
+
[Symbol.toStringTag]: { value: "Module" }
|
|
4
|
+
});
|
|
5
|
+
//#region \0rolldown/runtime.js
|
|
6
|
+
var __create = Object.create;
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
9
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
10
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
14
|
+
key = keys[i];
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
16
|
+
get: ((k) => from[k]).bind(null, key),
|
|
17
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
//#endregion
|
|
27
|
+
let react = require("react");
|
|
28
|
+
react = __toESM(react);
|
|
29
|
+
let react_native = require("react-native");
|
|
30
|
+
//#region src/constants.ts
|
|
31
|
+
const resizeMode = {
|
|
32
|
+
contain: "contain",
|
|
33
|
+
cover: "cover",
|
|
34
|
+
stretch: "stretch",
|
|
35
|
+
center: "center"
|
|
36
|
+
};
|
|
37
|
+
const priority = {
|
|
38
|
+
low: "low",
|
|
39
|
+
normal: "normal",
|
|
40
|
+
high: "high"
|
|
41
|
+
};
|
|
42
|
+
const cacheControl = {
|
|
43
|
+
immutable: "immutable",
|
|
44
|
+
web: "web",
|
|
45
|
+
cacheOnly: "cacheOnly"
|
|
46
|
+
};
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/index.web.tsx
|
|
49
|
+
const notSupported = {
|
|
50
|
+
ok: false,
|
|
51
|
+
error: "Not supported on the web"
|
|
52
|
+
};
|
|
53
|
+
function FastImageBase({ source, defaultSource, tintColor, blurRadius, onLoadStart, onLoad, onError, onLoadEnd, style, children, resizeMode: mode = "cover", forwardedRef, onLayout, pointerEvents, fallback: _fallback, recyclingKey: _recyclingKey, loop: _loop, imageRendering: _imageRendering, paused: _paused, transition: _transition, downsample: _downsample, onProgress: _onProgress, ...props }) {
|
|
54
|
+
const result = (0, react.useRef)(void 0);
|
|
55
|
+
const sent = (0, react.useRef)(Promise.resolve());
|
|
56
|
+
const image = (0, react.useRef)(null);
|
|
57
|
+
const uri = typeof source === "object" && source ? source.uri : void 0;
|
|
58
|
+
const webSource = typeof source === "number" ? source : uri ? { uri } : void 0;
|
|
59
|
+
return /* @__PURE__ */ react.default.createElement(react_native.View, {
|
|
60
|
+
style: [styles.container, style],
|
|
61
|
+
onLayout,
|
|
62
|
+
pointerEvents,
|
|
63
|
+
ref: forwardedRef
|
|
64
|
+
}, /* @__PURE__ */ react.default.createElement(react_native.Image, {
|
|
65
|
+
...props,
|
|
66
|
+
style: styles.image,
|
|
67
|
+
source: webSource,
|
|
68
|
+
defaultSource,
|
|
69
|
+
resizeMode: mode,
|
|
70
|
+
tintColor,
|
|
71
|
+
blurRadius,
|
|
72
|
+
ref: image,
|
|
73
|
+
onLoadStart,
|
|
74
|
+
onLoad: (event) => {
|
|
75
|
+
var _event$nativeEvent;
|
|
76
|
+
sent.current = loadedSize(event === null || event === void 0 || (_event$nativeEvent = event.nativeEvent) === null || _event$nativeEvent === void 0 ? void 0 : _event$nativeEvent.target, image.current, uri).then(({ width, height }) => {
|
|
77
|
+
result.current = {
|
|
78
|
+
ok: true,
|
|
79
|
+
width,
|
|
80
|
+
height
|
|
81
|
+
};
|
|
82
|
+
onLoad === null || onLoad === void 0 || onLoad({ nativeEvent: {
|
|
83
|
+
width,
|
|
84
|
+
height
|
|
85
|
+
} });
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
onError: (event) => {
|
|
89
|
+
var _event$nativeEvent$er, _event$nativeEvent2;
|
|
90
|
+
const error = String((_event$nativeEvent$er = event === null || event === void 0 || (_event$nativeEvent2 = event.nativeEvent) === null || _event$nativeEvent2 === void 0 ? void 0 : _event$nativeEvent2.error) !== null && _event$nativeEvent$er !== void 0 ? _event$nativeEvent$er : "Failed to load the image");
|
|
91
|
+
result.current = {
|
|
92
|
+
ok: false,
|
|
93
|
+
error
|
|
94
|
+
};
|
|
95
|
+
sent.current = Promise.resolve();
|
|
96
|
+
onError === null || onError === void 0 || onError({ nativeEvent: { error } });
|
|
97
|
+
},
|
|
98
|
+
onLoadEnd: () => {
|
|
99
|
+
sent.current.then(() => {
|
|
100
|
+
var _result$current;
|
|
101
|
+
onLoadEnd === null || onLoadEnd === void 0 || onLoadEnd((_result$current = result.current) !== null && _result$current !== void 0 ? _result$current : {
|
|
102
|
+
ok: false,
|
|
103
|
+
error: "Failed to load the image"
|
|
104
|
+
});
|
|
105
|
+
result.current = void 0;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}), children);
|
|
109
|
+
}
|
|
110
|
+
const FastImageMemo = (0, react.memo)(FastImageBase);
|
|
111
|
+
const FastImageComponent = (0, react.forwardRef)((props, ref) => /* @__PURE__ */ react.default.createElement(FastImageMemo, {
|
|
112
|
+
forwardedRef: ref,
|
|
113
|
+
...props
|
|
114
|
+
}));
|
|
115
|
+
FastImageComponent.displayName = "FastImage";
|
|
116
|
+
async function loadedSize(loaded, view, uri) {
|
|
117
|
+
var _view$querySelector;
|
|
118
|
+
if (loaded === null || loaded === void 0 ? void 0 : loaded.naturalWidth) return {
|
|
119
|
+
width: loaded.naturalWidth,
|
|
120
|
+
height: loaded.naturalHeight
|
|
121
|
+
};
|
|
122
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
123
|
+
const shown = view === null || view === void 0 || (_view$querySelector = view.querySelector) === null || _view$querySelector === void 0 ? void 0 : _view$querySelector.call(view, "img");
|
|
124
|
+
if (shown === null || shown === void 0 ? void 0 : shown.naturalWidth) return {
|
|
125
|
+
width: shown.naturalWidth,
|
|
126
|
+
height: shown.naturalHeight
|
|
127
|
+
};
|
|
128
|
+
const src = uri !== null && uri !== void 0 ? uri : shown === null || shown === void 0 ? void 0 : shown.src;
|
|
129
|
+
return src ? getSize(src) : {
|
|
130
|
+
width: 0,
|
|
131
|
+
height: 0
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function getSize(uri) {
|
|
135
|
+
return new Promise((resolve) => {
|
|
136
|
+
react_native.Image.getSize(uri, (width, height) => resolve({
|
|
137
|
+
width,
|
|
138
|
+
height
|
|
139
|
+
}), () => resolve({
|
|
140
|
+
width: 0,
|
|
141
|
+
height: 0
|
|
142
|
+
}));
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
const FastImage = FastImageComponent;
|
|
146
|
+
FastImage.resizeMode = resizeMode;
|
|
147
|
+
FastImage.cacheControl = cacheControl;
|
|
148
|
+
FastImage.priority = priority;
|
|
149
|
+
FastImage.preload = (sources) => Promise.all(sources.map((source) => {
|
|
150
|
+
const uri = source ? source.uri : void 0;
|
|
151
|
+
if (typeof uri !== "string" || !uri) return Promise.resolve({
|
|
152
|
+
ok: false,
|
|
153
|
+
error: "Invalid source: no uri",
|
|
154
|
+
uri
|
|
155
|
+
});
|
|
156
|
+
return react_native.Image.prefetch(uri).then(() => getSize(uri).then((size) => ({
|
|
157
|
+
ok: true,
|
|
158
|
+
uri,
|
|
159
|
+
...size
|
|
160
|
+
})), () => ({
|
|
161
|
+
ok: false,
|
|
162
|
+
error: "Failed to load the image",
|
|
163
|
+
uri
|
|
164
|
+
}));
|
|
165
|
+
}));
|
|
166
|
+
FastImage.clearMemoryCache = () => Promise.resolve();
|
|
167
|
+
FastImage.clearDiskCache = () => Promise.resolve();
|
|
168
|
+
FastImage.configureCache = () => Promise.resolve({});
|
|
169
|
+
FastImage.writeToCache = () => Promise.resolve(notSupported);
|
|
170
|
+
FastImage.getCachePath = () => Promise.resolve(notSupported);
|
|
171
|
+
const styles = react_native.StyleSheet.create({
|
|
172
|
+
container: { overflow: "hidden" },
|
|
173
|
+
image: {
|
|
174
|
+
position: "absolute",
|
|
175
|
+
top: 0,
|
|
176
|
+
left: 0,
|
|
177
|
+
width: "100%",
|
|
178
|
+
height: "100%"
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
const FastImageWithRef = FastImageComponent;
|
|
182
|
+
const FastImageBackground = (0, react.forwardRef)(({ style, imageStyle, imageRef, children, ...props }, ref) => /* @__PURE__ */ react.default.createElement(react_native.View, {
|
|
183
|
+
style,
|
|
184
|
+
ref
|
|
185
|
+
}, /* @__PURE__ */ react.default.createElement(FastImageWithRef, {
|
|
186
|
+
...props,
|
|
187
|
+
style: [react_native.StyleSheet.absoluteFill, imageStyle],
|
|
188
|
+
ref: imageRef
|
|
189
|
+
}), children));
|
|
190
|
+
FastImageBackground.displayName = "FastImageBackground";
|
|
191
|
+
//#endregion
|
|
192
|
+
exports.FastImageBackground = FastImageBackground;
|
|
193
|
+
exports.default = FastImage;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import type { ViewProps } from 'react-native/Libraries/Components/View/ViewPropTypes'
|
|
4
|
+
import type { SyntheticEvent } from 'react-native/Libraries/Types/CoreEventTypes'
|
|
5
|
+
|
|
6
|
+
export type OnLoadEvent = SyntheticEvent<
|
|
7
|
+
$ReadOnly<{
|
|
8
|
+
width: number,
|
|
9
|
+
height: number,
|
|
10
|
+
// The view's React tag. Missing on Android with the legacy architecture.
|
|
11
|
+
// TODO: make it required once the New Architecture is the minimum.
|
|
12
|
+
target?: number,
|
|
13
|
+
}>,
|
|
14
|
+
>
|
|
15
|
+
|
|
16
|
+
export type OnErrorEvent = SyntheticEvent<
|
|
17
|
+
$ReadOnly<{|
|
|
18
|
+
error: string,
|
|
19
|
+
|}>,
|
|
20
|
+
>
|
|
21
|
+
|
|
22
|
+
export type OnProgressEvent = SyntheticEvent<
|
|
23
|
+
$ReadOnly<{|
|
|
24
|
+
loaded: number,
|
|
25
|
+
total: number,
|
|
26
|
+
// loaded / total, from 0 to 1.
|
|
27
|
+
progress: number,
|
|
28
|
+
|}>,
|
|
29
|
+
>
|
|
30
|
+
|
|
31
|
+
export type ResizeMode = $ReadOnly<{|
|
|
32
|
+
contain: 'contain',
|
|
33
|
+
cover: 'cover',
|
|
34
|
+
stretch: 'stretch',
|
|
35
|
+
center: 'center',
|
|
36
|
+
|}>
|
|
37
|
+
|
|
38
|
+
export type Priority = $ReadOnly<{|
|
|
39
|
+
low: 'low',
|
|
40
|
+
normal: 'normal',
|
|
41
|
+
high: 'high',
|
|
42
|
+
|}>
|
|
43
|
+
|
|
44
|
+
export type CacheControl = $ReadOnly<{|
|
|
45
|
+
immutable: 'immutable',
|
|
46
|
+
web: 'web',
|
|
47
|
+
cacheOnly: 'cacheOnly',
|
|
48
|
+
|}>
|
|
49
|
+
|
|
50
|
+
export type ResizeModes = $Values<ResizeMode>
|
|
51
|
+
export type Priorities = $Values<Priority>
|
|
52
|
+
export type CacheControls = $Values<CacheControl>
|
|
53
|
+
|
|
54
|
+
export type LoadResult =
|
|
55
|
+
| {| ok: true, width: number, height: number |}
|
|
56
|
+
| {| ok: false, error: string |}
|
|
57
|
+
|
|
58
|
+
export type CacheLimits = {|
|
|
59
|
+
maxDiskSize?: ?number,
|
|
60
|
+
maxDiskAge?: ?number,
|
|
61
|
+
maxMemorySize?: ?number,
|
|
62
|
+
|}
|
|
63
|
+
|
|
64
|
+
export type CacheState = {|
|
|
65
|
+
maxDiskSize?: number,
|
|
66
|
+
maxDiskAge?: number,
|
|
67
|
+
maxMemorySize?: number,
|
|
68
|
+
diskSize?: number,
|
|
69
|
+
|}
|
|
70
|
+
|
|
71
|
+
export type CachePathResult =
|
|
72
|
+
| {| ok: true, path: string |}
|
|
73
|
+
| {| ok: false, error: string |}
|
|
74
|
+
|
|
75
|
+
export type Transition = $ReadOnly<{|
|
|
76
|
+
duration?: ?number,
|
|
77
|
+
betweenImages?: ?boolean,
|
|
78
|
+
skipOnCacheHit?: ?('none' | 'memory' | 'all'),
|
|
79
|
+
|}>
|
|
80
|
+
|
|
81
|
+
export type PreloadSuccess = {|
|
|
82
|
+
uri: string,
|
|
83
|
+
ok: true,
|
|
84
|
+
width: number,
|
|
85
|
+
height: number,
|
|
86
|
+
|}
|
|
87
|
+
|
|
88
|
+
export type PreloadFailure = {|
|
|
89
|
+
uri?: string,
|
|
90
|
+
ok: false,
|
|
91
|
+
error: string,
|
|
92
|
+
|}
|
|
93
|
+
|
|
94
|
+
export type PreloadResult = PreloadSuccess | PreloadFailure
|
|
95
|
+
|
|
96
|
+
export type PreloadFn = (
|
|
97
|
+
sources: Array<FastImageSource>,
|
|
98
|
+
) => Promise<Array<PreloadResult>>
|
|
99
|
+
export type FastImageSource = {
|
|
100
|
+
uri?: string,
|
|
101
|
+
headers?: Object,
|
|
102
|
+
priority?: Priorities,
|
|
103
|
+
cache?: CacheControls,
|
|
104
|
+
cacheKey?: string,
|
|
105
|
+
memoryCache?: boolean,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export type FastImageProps = $ReadOnly<{|
|
|
109
|
+
...ViewProps,
|
|
110
|
+
onError?: ?(event: OnErrorEvent) => void,
|
|
111
|
+
onLoad?: ?(event: OnLoadEvent) => void,
|
|
112
|
+
onLoadEnd?: ?(result: LoadResult) => void,
|
|
113
|
+
onLoadStart?: ?() => void,
|
|
114
|
+
onProgress?: ?(event: OnProgressEvent) => void,
|
|
115
|
+
|
|
116
|
+
source?: ?(FastImageSource | number),
|
|
117
|
+
defaultSource?: ?number,
|
|
118
|
+
|
|
119
|
+
tintColor?: number | string,
|
|
120
|
+
resizeMode?: ?ResizeModes,
|
|
121
|
+
fallback?: ?boolean,
|
|
122
|
+
recyclingKey?: ?string,
|
|
123
|
+
loop?: ?(boolean | number),
|
|
124
|
+
imageRendering?: ?('auto' | 'smooth' | 'pixelated'),
|
|
125
|
+
paused?: ?boolean,
|
|
126
|
+
transition?: ?(boolean | number | Transition),
|
|
127
|
+
downsample?: ?boolean,
|
|
128
|
+
blurRadius?: ?number,
|
|
129
|
+
testID?: ?string,
|
|
130
|
+
|}>
|
|
131
|
+
|
|
132
|
+
export type FastImageBackgroundProps = $ReadOnly<{|
|
|
133
|
+
...FastImageProps,
|
|
134
|
+
imageStyle?: $PropertyType<ViewProps, 'style'>,
|
|
135
|
+
imageRef?: React$Ref<any>,
|
|
136
|
+
children?: React$Node,
|
|
137
|
+
|}>
|
|
138
|
+
|
|
139
|
+
declare export var FastImageBackground: React$ComponentType<FastImageBackgroundProps>
|
|
140
|
+
|
|
141
|
+
declare export default class FastImage extends React$Component<FastImageProps> {
|
|
142
|
+
static resizeMode: ResizeMode;
|
|
143
|
+
static priority: Priority;
|
|
144
|
+
static cacheControl: CacheControl;
|
|
145
|
+
static preload: PreloadFn;
|
|
146
|
+
static clearMemoryCache: () => Promise<void>;
|
|
147
|
+
static clearDiskCache: () => Promise<void>;
|
|
148
|
+
static getCachePath: (source: FastImageSource) => Promise<CachePathResult>;
|
|
149
|
+
static configureCache: (limits?: CacheLimits) => Promise<CacheState>;
|
|
150
|
+
static writeToCache: (
|
|
151
|
+
source: FastImageSource,
|
|
152
|
+
file: string,
|
|
153
|
+
) => Promise<CachePathResult>;
|
|
154
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,25 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { LayoutChangeEvent, StyleProp, ViewStyle, ImageRequireSource, AccessibilityProps, ViewProps } from 'react-native';
|
|
3
|
+
import { cacheControl, priority, resizeMode } from './constants';
|
|
3
4
|
type ColorValue = NonNullable<ViewStyle['backgroundColor']>;
|
|
4
5
|
export type ResizeMode = 'contain' | 'cover' | 'stretch' | 'center';
|
|
5
|
-
declare const resizeMode: {
|
|
6
|
-
readonly contain: 'contain';
|
|
7
|
-
readonly cover: 'cover';
|
|
8
|
-
readonly stretch: 'stretch';
|
|
9
|
-
readonly center: 'center';
|
|
10
|
-
};
|
|
11
6
|
export type Priority = 'low' | 'normal' | 'high';
|
|
12
|
-
declare const priority: {
|
|
13
|
-
readonly low: 'low';
|
|
14
|
-
readonly normal: 'normal';
|
|
15
|
-
readonly high: 'high';
|
|
16
|
-
};
|
|
17
7
|
export type Cache = 'immutable' | 'web' | 'cacheOnly';
|
|
18
|
-
declare const cacheControl: {
|
|
19
|
-
readonly immutable: 'immutable';
|
|
20
|
-
readonly web: 'web';
|
|
21
|
-
readonly cacheOnly: 'cacheOnly';
|
|
22
|
-
};
|
|
23
8
|
export type Source = {
|
|
24
9
|
uri?: string;
|
|
25
10
|
headers?: {
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { forwardRef, memo, useRef } from "react";
|
|
2
2
|
import { Image, NativeModules, Platform, StyleSheet, View, requireNativeComponent } from "react-native";
|
|
3
|
-
//#region src/
|
|
3
|
+
//#region src/constants.ts
|
|
4
4
|
const resizeMode = {
|
|
5
5
|
contain: "contain",
|
|
6
6
|
cover: "cover",
|
|
@@ -17,6 +17,8 @@ const cacheControl = {
|
|
|
17
17
|
web: "web",
|
|
18
18
|
cacheOnly: "cacheOnly"
|
|
19
19
|
};
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/index.tsx
|
|
20
22
|
const resolveDefaultSource = (defaultSource) => {
|
|
21
23
|
if (!defaultSource) return null;
|
|
22
24
|
if (Platform.OS === "android") {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { FastImageBackgroundProps, FastImageProps, FastImageStaticProperties } from './index';
|
|
3
|
+
export type * from './index';
|
|
4
|
+
declare const FastImage: React.ComponentType<FastImageProps> & FastImageStaticProperties;
|
|
5
|
+
export declare const FastImageBackground: React.ComponentType<FastImageBackgroundProps>;
|
|
6
|
+
export default FastImage;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import React, { forwardRef, memo, useRef } from "react";
|
|
2
|
+
import { Image, StyleSheet, View } from "react-native";
|
|
3
|
+
//#region src/constants.ts
|
|
4
|
+
const resizeMode = {
|
|
5
|
+
contain: "contain",
|
|
6
|
+
cover: "cover",
|
|
7
|
+
stretch: "stretch",
|
|
8
|
+
center: "center"
|
|
9
|
+
};
|
|
10
|
+
const priority = {
|
|
11
|
+
low: "low",
|
|
12
|
+
normal: "normal",
|
|
13
|
+
high: "high"
|
|
14
|
+
};
|
|
15
|
+
const cacheControl = {
|
|
16
|
+
immutable: "immutable",
|
|
17
|
+
web: "web",
|
|
18
|
+
cacheOnly: "cacheOnly"
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/index.web.tsx
|
|
22
|
+
const notSupported = {
|
|
23
|
+
ok: false,
|
|
24
|
+
error: "Not supported on the web"
|
|
25
|
+
};
|
|
26
|
+
function FastImageBase({ source, defaultSource, tintColor, blurRadius, onLoadStart, onLoad, onError, onLoadEnd, style, children, resizeMode: mode = "cover", forwardedRef, onLayout, pointerEvents, fallback: _fallback, recyclingKey: _recyclingKey, loop: _loop, imageRendering: _imageRendering, paused: _paused, transition: _transition, downsample: _downsample, onProgress: _onProgress, ...props }) {
|
|
27
|
+
const result = useRef(void 0);
|
|
28
|
+
const sent = useRef(Promise.resolve());
|
|
29
|
+
const image = useRef(null);
|
|
30
|
+
const uri = typeof source === "object" && source ? source.uri : void 0;
|
|
31
|
+
const webSource = typeof source === "number" ? source : uri ? { uri } : void 0;
|
|
32
|
+
return /* @__PURE__ */ React.createElement(View, {
|
|
33
|
+
style: [styles.container, style],
|
|
34
|
+
onLayout,
|
|
35
|
+
pointerEvents,
|
|
36
|
+
ref: forwardedRef
|
|
37
|
+
}, /* @__PURE__ */ React.createElement(Image, {
|
|
38
|
+
...props,
|
|
39
|
+
style: styles.image,
|
|
40
|
+
source: webSource,
|
|
41
|
+
defaultSource,
|
|
42
|
+
resizeMode: mode,
|
|
43
|
+
tintColor,
|
|
44
|
+
blurRadius,
|
|
45
|
+
ref: image,
|
|
46
|
+
onLoadStart,
|
|
47
|
+
onLoad: (event) => {
|
|
48
|
+
var _event$nativeEvent;
|
|
49
|
+
sent.current = loadedSize(event === null || event === void 0 || (_event$nativeEvent = event.nativeEvent) === null || _event$nativeEvent === void 0 ? void 0 : _event$nativeEvent.target, image.current, uri).then(({ width, height }) => {
|
|
50
|
+
result.current = {
|
|
51
|
+
ok: true,
|
|
52
|
+
width,
|
|
53
|
+
height
|
|
54
|
+
};
|
|
55
|
+
onLoad === null || onLoad === void 0 || onLoad({ nativeEvent: {
|
|
56
|
+
width,
|
|
57
|
+
height
|
|
58
|
+
} });
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
onError: (event) => {
|
|
62
|
+
var _event$nativeEvent$er, _event$nativeEvent2;
|
|
63
|
+
const error = String((_event$nativeEvent$er = event === null || event === void 0 || (_event$nativeEvent2 = event.nativeEvent) === null || _event$nativeEvent2 === void 0 ? void 0 : _event$nativeEvent2.error) !== null && _event$nativeEvent$er !== void 0 ? _event$nativeEvent$er : "Failed to load the image");
|
|
64
|
+
result.current = {
|
|
65
|
+
ok: false,
|
|
66
|
+
error
|
|
67
|
+
};
|
|
68
|
+
sent.current = Promise.resolve();
|
|
69
|
+
onError === null || onError === void 0 || onError({ nativeEvent: { error } });
|
|
70
|
+
},
|
|
71
|
+
onLoadEnd: () => {
|
|
72
|
+
sent.current.then(() => {
|
|
73
|
+
var _result$current;
|
|
74
|
+
onLoadEnd === null || onLoadEnd === void 0 || onLoadEnd((_result$current = result.current) !== null && _result$current !== void 0 ? _result$current : {
|
|
75
|
+
ok: false,
|
|
76
|
+
error: "Failed to load the image"
|
|
77
|
+
});
|
|
78
|
+
result.current = void 0;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}), children);
|
|
82
|
+
}
|
|
83
|
+
const FastImageMemo = memo(FastImageBase);
|
|
84
|
+
const FastImageComponent = forwardRef((props, ref) => /* @__PURE__ */ React.createElement(FastImageMemo, {
|
|
85
|
+
forwardedRef: ref,
|
|
86
|
+
...props
|
|
87
|
+
}));
|
|
88
|
+
FastImageComponent.displayName = "FastImage";
|
|
89
|
+
async function loadedSize(loaded, view, uri) {
|
|
90
|
+
var _view$querySelector;
|
|
91
|
+
if (loaded === null || loaded === void 0 ? void 0 : loaded.naturalWidth) return {
|
|
92
|
+
width: loaded.naturalWidth,
|
|
93
|
+
height: loaded.naturalHeight
|
|
94
|
+
};
|
|
95
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
96
|
+
const shown = view === null || view === void 0 || (_view$querySelector = view.querySelector) === null || _view$querySelector === void 0 ? void 0 : _view$querySelector.call(view, "img");
|
|
97
|
+
if (shown === null || shown === void 0 ? void 0 : shown.naturalWidth) return {
|
|
98
|
+
width: shown.naturalWidth,
|
|
99
|
+
height: shown.naturalHeight
|
|
100
|
+
};
|
|
101
|
+
const src = uri !== null && uri !== void 0 ? uri : shown === null || shown === void 0 ? void 0 : shown.src;
|
|
102
|
+
return src ? getSize(src) : {
|
|
103
|
+
width: 0,
|
|
104
|
+
height: 0
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function getSize(uri) {
|
|
108
|
+
return new Promise((resolve) => {
|
|
109
|
+
Image.getSize(uri, (width, height) => resolve({
|
|
110
|
+
width,
|
|
111
|
+
height
|
|
112
|
+
}), () => resolve({
|
|
113
|
+
width: 0,
|
|
114
|
+
height: 0
|
|
115
|
+
}));
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
const FastImage = FastImageComponent;
|
|
119
|
+
FastImage.resizeMode = resizeMode;
|
|
120
|
+
FastImage.cacheControl = cacheControl;
|
|
121
|
+
FastImage.priority = priority;
|
|
122
|
+
FastImage.preload = (sources) => Promise.all(sources.map((source) => {
|
|
123
|
+
const uri = source ? source.uri : void 0;
|
|
124
|
+
if (typeof uri !== "string" || !uri) return Promise.resolve({
|
|
125
|
+
ok: false,
|
|
126
|
+
error: "Invalid source: no uri",
|
|
127
|
+
uri
|
|
128
|
+
});
|
|
129
|
+
return Image.prefetch(uri).then(() => getSize(uri).then((size) => ({
|
|
130
|
+
ok: true,
|
|
131
|
+
uri,
|
|
132
|
+
...size
|
|
133
|
+
})), () => ({
|
|
134
|
+
ok: false,
|
|
135
|
+
error: "Failed to load the image",
|
|
136
|
+
uri
|
|
137
|
+
}));
|
|
138
|
+
}));
|
|
139
|
+
FastImage.clearMemoryCache = () => Promise.resolve();
|
|
140
|
+
FastImage.clearDiskCache = () => Promise.resolve();
|
|
141
|
+
FastImage.configureCache = () => Promise.resolve({});
|
|
142
|
+
FastImage.writeToCache = () => Promise.resolve(notSupported);
|
|
143
|
+
FastImage.getCachePath = () => Promise.resolve(notSupported);
|
|
144
|
+
const styles = StyleSheet.create({
|
|
145
|
+
container: { overflow: "hidden" },
|
|
146
|
+
image: {
|
|
147
|
+
position: "absolute",
|
|
148
|
+
top: 0,
|
|
149
|
+
left: 0,
|
|
150
|
+
width: "100%",
|
|
151
|
+
height: "100%"
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
const FastImageWithRef = FastImageComponent;
|
|
155
|
+
const FastImageBackground = forwardRef(({ style, imageStyle, imageRef, children, ...props }, ref) => /* @__PURE__ */ React.createElement(View, {
|
|
156
|
+
style,
|
|
157
|
+
ref
|
|
158
|
+
}, /* @__PURE__ */ React.createElement(FastImageWithRef, {
|
|
159
|
+
...props,
|
|
160
|
+
style: [StyleSheet.absoluteFill, imageStyle],
|
|
161
|
+
ref: imageRef
|
|
162
|
+
}), children));
|
|
163
|
+
FastImageBackground.displayName = "FastImageBackground";
|
|
164
|
+
//#endregion
|
|
165
|
+
export { FastImageBackground, FastImage as default };
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import type { ViewProps } from 'react-native/Libraries/Components/View/ViewPropTypes'
|
|
4
|
+
import type { SyntheticEvent } from 'react-native/Libraries/Types/CoreEventTypes'
|
|
5
|
+
|
|
6
|
+
export type OnLoadEvent = SyntheticEvent<
|
|
7
|
+
$ReadOnly<{
|
|
8
|
+
width: number,
|
|
9
|
+
height: number,
|
|
10
|
+
// The view's React tag. Missing on Android with the legacy architecture.
|
|
11
|
+
// TODO: make it required once the New Architecture is the minimum.
|
|
12
|
+
target?: number,
|
|
13
|
+
}>,
|
|
14
|
+
>
|
|
15
|
+
|
|
16
|
+
export type OnErrorEvent = SyntheticEvent<
|
|
17
|
+
$ReadOnly<{|
|
|
18
|
+
error: string,
|
|
19
|
+
|}>,
|
|
20
|
+
>
|
|
21
|
+
|
|
22
|
+
export type OnProgressEvent = SyntheticEvent<
|
|
23
|
+
$ReadOnly<{|
|
|
24
|
+
loaded: number,
|
|
25
|
+
total: number,
|
|
26
|
+
// loaded / total, from 0 to 1.
|
|
27
|
+
progress: number,
|
|
28
|
+
|}>,
|
|
29
|
+
>
|
|
30
|
+
|
|
31
|
+
export type ResizeMode = $ReadOnly<{|
|
|
32
|
+
contain: 'contain',
|
|
33
|
+
cover: 'cover',
|
|
34
|
+
stretch: 'stretch',
|
|
35
|
+
center: 'center',
|
|
36
|
+
|}>
|
|
37
|
+
|
|
38
|
+
export type Priority = $ReadOnly<{|
|
|
39
|
+
low: 'low',
|
|
40
|
+
normal: 'normal',
|
|
41
|
+
high: 'high',
|
|
42
|
+
|}>
|
|
43
|
+
|
|
44
|
+
export type CacheControl = $ReadOnly<{|
|
|
45
|
+
immutable: 'immutable',
|
|
46
|
+
web: 'web',
|
|
47
|
+
cacheOnly: 'cacheOnly',
|
|
48
|
+
|}>
|
|
49
|
+
|
|
50
|
+
export type ResizeModes = $Values<ResizeMode>
|
|
51
|
+
export type Priorities = $Values<Priority>
|
|
52
|
+
export type CacheControls = $Values<CacheControl>
|
|
53
|
+
|
|
54
|
+
export type LoadResult =
|
|
55
|
+
| {| ok: true, width: number, height: number |}
|
|
56
|
+
| {| ok: false, error: string |}
|
|
57
|
+
|
|
58
|
+
export type CacheLimits = {|
|
|
59
|
+
maxDiskSize?: ?number,
|
|
60
|
+
maxDiskAge?: ?number,
|
|
61
|
+
maxMemorySize?: ?number,
|
|
62
|
+
|}
|
|
63
|
+
|
|
64
|
+
export type CacheState = {|
|
|
65
|
+
maxDiskSize?: number,
|
|
66
|
+
maxDiskAge?: number,
|
|
67
|
+
maxMemorySize?: number,
|
|
68
|
+
diskSize?: number,
|
|
69
|
+
|}
|
|
70
|
+
|
|
71
|
+
export type CachePathResult =
|
|
72
|
+
| {| ok: true, path: string |}
|
|
73
|
+
| {| ok: false, error: string |}
|
|
74
|
+
|
|
75
|
+
export type Transition = $ReadOnly<{|
|
|
76
|
+
duration?: ?number,
|
|
77
|
+
betweenImages?: ?boolean,
|
|
78
|
+
skipOnCacheHit?: ?('none' | 'memory' | 'all'),
|
|
79
|
+
|}>
|
|
80
|
+
|
|
81
|
+
export type PreloadSuccess = {|
|
|
82
|
+
uri: string,
|
|
83
|
+
ok: true,
|
|
84
|
+
width: number,
|
|
85
|
+
height: number,
|
|
86
|
+
|}
|
|
87
|
+
|
|
88
|
+
export type PreloadFailure = {|
|
|
89
|
+
uri?: string,
|
|
90
|
+
ok: false,
|
|
91
|
+
error: string,
|
|
92
|
+
|}
|
|
93
|
+
|
|
94
|
+
export type PreloadResult = PreloadSuccess | PreloadFailure
|
|
95
|
+
|
|
96
|
+
export type PreloadFn = (
|
|
97
|
+
sources: Array<FastImageSource>,
|
|
98
|
+
) => Promise<Array<PreloadResult>>
|
|
99
|
+
export type FastImageSource = {
|
|
100
|
+
uri?: string,
|
|
101
|
+
headers?: Object,
|
|
102
|
+
priority?: Priorities,
|
|
103
|
+
cache?: CacheControls,
|
|
104
|
+
cacheKey?: string,
|
|
105
|
+
memoryCache?: boolean,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export type FastImageProps = $ReadOnly<{|
|
|
109
|
+
...ViewProps,
|
|
110
|
+
onError?: ?(event: OnErrorEvent) => void,
|
|
111
|
+
onLoad?: ?(event: OnLoadEvent) => void,
|
|
112
|
+
onLoadEnd?: ?(result: LoadResult) => void,
|
|
113
|
+
onLoadStart?: ?() => void,
|
|
114
|
+
onProgress?: ?(event: OnProgressEvent) => void,
|
|
115
|
+
|
|
116
|
+
source?: ?(FastImageSource | number),
|
|
117
|
+
defaultSource?: ?number,
|
|
118
|
+
|
|
119
|
+
tintColor?: number | string,
|
|
120
|
+
resizeMode?: ?ResizeModes,
|
|
121
|
+
fallback?: ?boolean,
|
|
122
|
+
recyclingKey?: ?string,
|
|
123
|
+
loop?: ?(boolean | number),
|
|
124
|
+
imageRendering?: ?('auto' | 'smooth' | 'pixelated'),
|
|
125
|
+
paused?: ?boolean,
|
|
126
|
+
transition?: ?(boolean | number | Transition),
|
|
127
|
+
downsample?: ?boolean,
|
|
128
|
+
blurRadius?: ?number,
|
|
129
|
+
testID?: ?string,
|
|
130
|
+
|}>
|
|
131
|
+
|
|
132
|
+
export type FastImageBackgroundProps = $ReadOnly<{|
|
|
133
|
+
...FastImageProps,
|
|
134
|
+
imageStyle?: $PropertyType<ViewProps, 'style'>,
|
|
135
|
+
imageRef?: React$Ref<any>,
|
|
136
|
+
children?: React$Node,
|
|
137
|
+
|}>
|
|
138
|
+
|
|
139
|
+
declare export var FastImageBackground: React$ComponentType<FastImageBackgroundProps>
|
|
140
|
+
|
|
141
|
+
declare export default class FastImage extends React$Component<FastImageProps> {
|
|
142
|
+
static resizeMode: ResizeMode;
|
|
143
|
+
static priority: Priority;
|
|
144
|
+
static cacheControl: CacheControl;
|
|
145
|
+
static preload: PreloadFn;
|
|
146
|
+
static clearMemoryCache: () => Promise<void>;
|
|
147
|
+
static clearDiskCache: () => Promise<void>;
|
|
148
|
+
static getCachePath: (source: FastImageSource) => Promise<CachePathResult>;
|
|
149
|
+
static configureCache: (limits?: CacheLimits) => Promise<CacheState>;
|
|
150
|
+
static writeToCache: (
|
|
151
|
+
source: FastImageSource,
|
|
152
|
+
file: string,
|
|
153
|
+
) => Promise<CachePathResult>;
|
|
154
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-fast-image",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.23.0",
|
|
4
4
|
"description": "🚩 FastImage, performant React Native image component.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cache",
|
|
@@ -19,8 +19,10 @@
|
|
|
19
19
|
},
|
|
20
20
|
"license": "(MIT AND Apache-2.0)",
|
|
21
21
|
"author": "Dylan Vann <dylan@dylanvann.com> (https://dylanvann.com)",
|
|
22
|
-
"main": "dist/index.cjs
|
|
23
|
-
"module": "dist/index
|
|
22
|
+
"main": "dist/index.cjs",
|
|
23
|
+
"module": "dist/index",
|
|
24
|
+
"react-native": "dist/index.cjs",
|
|
25
|
+
"browser": "dist/index.web.js",
|
|
24
26
|
"typings": "dist/index.d.ts",
|
|
25
27
|
"files": [
|
|
26
28
|
"android/build.gradle",
|
|
@@ -34,7 +36,7 @@
|
|
|
34
36
|
"RNFastImage.podspec"
|
|
35
37
|
],
|
|
36
38
|
"scripts": {
|
|
37
|
-
"build": "rm -rf dist && tsc -p tsconfig.build.json && rolldown -c &&
|
|
39
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json && rolldown -c && for f in index index.cjs index.web index.cjs.web; do cp src/index.js.flow dist/$f.js.flow; done",
|
|
38
40
|
"lint": "oxlint",
|
|
39
41
|
"release": "semantic-release",
|
|
40
42
|
"test": "bun test",
|