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.
Files changed (78) hide show
  1. package/README.md +97 -61
  2. package/RNFastImage.podspec +14 -9
  3. package/android/build.gradle +21 -47
  4. package/android/consumer-rules.pro +7 -7
  5. package/android/src/main/AndroidManifest.xml +1 -2
  6. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageAnimatable.java +1 -1
  7. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageAnimated.java +2 -2
  8. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageApng.java +2 -2
  9. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageBlur.java +4 -6
  10. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageCacheControl.java +1 -1
  11. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageCacheLimits.java +4 -1
  12. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageCacheWrite.java +1 -1
  13. package/android/src/main/java/com/fastimage/FastImageCrop.java +92 -0
  14. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageEvent.java +2 -3
  15. package/android/src/main/java/com/fastimage/FastImageEvents.java +74 -0
  16. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageGif.java +1 -1
  17. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageGlide.java +13 -3
  18. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageGlideModule.java +1 -1
  19. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageKeyedGlideUrl.java +1 -1
  20. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageOkHttpProgressGlideModule.java +49 -14
  21. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageRequestListener.java +6 -1
  22. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSharedDownloads.java +1 -1
  23. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSource.java +12 -1
  24. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSourceSize.java +12 -2
  25. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSvg.java +3 -3
  26. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageSvgRenderer.java +1 -1
  27. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageUrl.java +1 -1
  28. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageViewConverter.java +24 -9
  29. package/android/src/main/java/com/fastimage/FastImageViewManager.java +591 -0
  30. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageViewModule.java +50 -28
  31. package/android/src/main/java/com/fastimage/FastImageViewPackage.java +51 -0
  32. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageViewWithUrl.java +352 -126
  33. package/android/src/main/java/com/{dylanvann/fastimage → fastimage}/FastImageWebGlideUrl.java +1 -1
  34. package/app.plugin.js +2 -7
  35. package/dist/index.cjs.js +276 -157
  36. package/dist/index.cjs.js.flow +34 -17
  37. package/dist/index.cjs.web.js +211 -61
  38. package/dist/index.cjs.web.js.flow +34 -17
  39. package/dist/index.d.ts +108 -58
  40. package/dist/index.js +278 -159
  41. package/dist/index.js.flow +34 -17
  42. package/dist/index.web.js +212 -62
  43. package/dist/index.web.js.flow +34 -17
  44. package/dist/objectFit.d.ts +2 -2
  45. package/dist/objectPosition.d.ts +42 -0
  46. package/dist/specs/FastImageViewNativeComponent.d.ts +48 -0
  47. package/dist/specs/NativeFastImageModule.d.ts +11 -0
  48. package/dist/warnings.d.ts +3 -0
  49. package/ios/FastImage/FFFDownsampledImage.h +4 -8
  50. package/ios/FastImage/FFFDownsampledImage.m +0 -34
  51. package/ios/FastImage/FFFastImageModule.h +8 -0
  52. package/ios/FastImage/{FFFastImageViewManager.m → FFFastImageModule.mm} +89 -59
  53. package/ios/FastImage/FFFastImageSource.h +4 -0
  54. package/ios/FastImage/FFFastImageSource.m +5 -1
  55. package/ios/FastImage/FFFastImageView.h +36 -7
  56. package/ios/FastImage/FFFastImageView.m +229 -172
  57. package/ios/FastImage/FFFastImageViewComponentView.h +11 -0
  58. package/ios/FastImage/FFFastImageViewComponentView.mm +325 -0
  59. package/ios/FastImage/RCTConvert+FFFastImage.h +1 -1
  60. package/ios/FastImage/RCTConvert+FFFastImage.m +9 -10
  61. package/package.json +28 -9
  62. package/src/constants.ts +28 -0
  63. package/src/index.js.flow +180 -0
  64. package/src/index.tsx +1128 -0
  65. package/src/index.web.tsx +548 -0
  66. package/src/objectFit.ts +48 -0
  67. package/src/objectPosition.ts +243 -0
  68. package/src/specs/FastImageViewNativeComponent.ts +83 -0
  69. package/src/specs/NativeFastImageModule.ts +35 -0
  70. package/src/warnings.ts +37 -0
  71. package/android/src/main/AndroidManifestNew.xml +0 -3
  72. package/android/src/main/java/com/dylanvann/fastimage/FastImageCookieHandler.java +0 -63
  73. package/android/src/main/java/com/dylanvann/fastimage/FastImageEvents.java +0 -49
  74. package/android/src/main/java/com/dylanvann/fastimage/FastImageProgressListener.java +0 -18
  75. package/android/src/main/java/com/dylanvann/fastimage/FastImageShadowNode.java +0 -21
  76. package/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java +0 -379
  77. package/android/src/main/java/com/dylanvann/fastimage/FastImageViewPackage.java +0 -27
  78. package/ios/FastImage/FFFastImageViewManager.h +0 -5
@@ -0,0 +1,325 @@
1
+ #import "FFFastImageViewComponentView.h"
2
+
3
+ #import <React/RCTConversions.h>
4
+ #import <React/RCTConvert.h>
5
+ #import <react/renderer/components/RNFastImageSpec/ComponentDescriptors.h>
6
+ #import <react/renderer/components/RNFastImageSpec/EventEmitters.h>
7
+ #import <react/renderer/components/RNFastImageSpec/Props.h>
8
+ #import <react/renderer/components/RNFastImageSpec/RCTComponentViewHelpers.h>
9
+
10
+ #import "FFFastImageView.h"
11
+ #import "RCTConvert+FFFastImage.h"
12
+
13
+ using namespace facebook::react;
14
+
15
+ // A string prop: nil when it's empty (not set).
16
+ static NSString *_Nullable FFFString(const std::string &value)
17
+ {
18
+ return value.empty() ? nil : [NSString stringWithUTF8String:value.c_str()];
19
+ }
20
+
21
+ // A value from JS as the objects React Native's converters (RCTConvert) take,
22
+ // with NSNull for null. (React Native's own converters aren't available to a
23
+ // library: React/RCTFollyConvert.h is a private header of React-Core, and
24
+ // react/utils/FollyConvert.h isn't on a library's header search paths when
25
+ // the app builds React Native from source with use_frameworks!, e.g. 0.83's.)
26
+ static id FFFObjectFromDynamic(const folly::dynamic &value)
27
+ {
28
+ switch (value.type()) {
29
+ case folly::dynamic::BOOL:
30
+ return @(value.getBool());
31
+ case folly::dynamic::INT64:
32
+ return @(value.getInt());
33
+ case folly::dynamic::DOUBLE:
34
+ return @(value.getDouble());
35
+ case folly::dynamic::STRING: {
36
+ const std::string &string = value.getString();
37
+ return [[NSString alloc] initWithBytes:string.data() length:string.size() encoding:NSUTF8StringEncoding] ?: @"";
38
+ }
39
+ case folly::dynamic::ARRAY: {
40
+ NSMutableArray *array = [NSMutableArray arrayWithCapacity:value.size()];
41
+ for (const auto &item : value) {
42
+ [array addObject:FFFObjectFromDynamic(item)];
43
+ }
44
+ return array;
45
+ }
46
+ case folly::dynamic::OBJECT: {
47
+ NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:value.size()];
48
+ for (const auto &pair : value.items()) {
49
+ if (pair.first.isString()) {
50
+ // As a string value: never nil (dictionary[nil] throws).
51
+ dictionary[FFFObjectFromDynamic(pair.first)] = FFFObjectFromDynamic(pair.second);
52
+ }
53
+ }
54
+ return dictionary;
55
+ }
56
+ default:
57
+ return (id)kCFNull;
58
+ }
59
+ }
60
+
61
+ // An event's payload (dictionaries of strings, numbers and booleans) for the
62
+ // event emitter.
63
+ static folly::dynamic FFFDynamicFromObject(id value)
64
+ {
65
+ if ([value isKindOfClass:NSDictionary.class]) {
66
+ folly::dynamic object = folly::dynamic::object();
67
+ for (id key in (NSDictionary *)value) {
68
+ if ([key isKindOfClass:NSString.class]) {
69
+ object[RCTStringFromNSString(key)] = FFFDynamicFromObject(((NSDictionary *)value)[key]);
70
+ }
71
+ }
72
+ return object;
73
+ }
74
+ if ([value isKindOfClass:NSArray.class]) {
75
+ folly::dynamic array = folly::dynamic::array();
76
+ for (id item in (NSArray *)value) {
77
+ array.push_back(FFFDynamicFromObject(item));
78
+ }
79
+ return array;
80
+ }
81
+ if ([value isKindOfClass:NSString.class]) {
82
+ // "" when it has no UTF-8 form (UTF8String is NULL for a string with
83
+ // a lone surrogate), as React Native's conversions do.
84
+ return RCTStringFromNSString(value);
85
+ }
86
+ if ([value isKindOfClass:NSNumber.class]) {
87
+ if (CFGetTypeID((__bridge CFTypeRef)value) == CFBooleanGetTypeID()) {
88
+ return (bool)[value boolValue];
89
+ }
90
+ if (CFNumberIsFloatType((__bridge CFNumberRef)value)) {
91
+ return [value doubleValue];
92
+ }
93
+ return (int64_t)[value longLongValue];
94
+ }
95
+ return nullptr;
96
+ }
97
+
98
+ // A prop of any type (a source, sources, defaultSource) as JSON: nil when
99
+ // it's null (not set).
100
+ static id _Nullable FFFJSON(const folly::dynamic &value)
101
+ {
102
+ return value.isNull() ? nil : FFFObjectFromDynamic(value);
103
+ }
104
+
105
+ // The events JS has a handler for: the handledEvents prop's bits (see
106
+ // src/specs/FastImageViewNativeComponent.ts).
107
+ typedef NS_OPTIONS(int32_t, FFFEvent) {
108
+ FFFEventLoadStart = 1 << 0,
109
+ FFFEventProgress = 1 << 1,
110
+ FFFEventLoad = 1 << 2,
111
+ FFFEventError = 1 << 3,
112
+ FFFEventLoadEnd = 1 << 4,
113
+ };
114
+
115
+ @interface FFFastImageViewComponentView () <RCTFastImageViewViewProtocol>
116
+ @end
117
+
118
+ @implementation FFFastImageViewComponentView {
119
+ FFFastImageView *_imageView;
120
+ // The props aren't on the image view yet (a new one): set them all,
121
+ // rather than the ones that changed.
122
+ BOOL _setsAllProps;
123
+ BOOL _propsChanged;
124
+ }
125
+
126
+ + (ComponentDescriptorProvider)componentDescriptorProvider
127
+ {
128
+ return concreteComponentDescriptorProvider<FastImageViewComponentDescriptor>();
129
+ }
130
+
131
+ - (instancetype)initWithFrame:(CGRect)frame
132
+ {
133
+ if (self = [super initWithFrame:frame]) {
134
+ static const auto defaultProps = std::make_shared<const FastImageViewProps>();
135
+ _props = defaultProps;
136
+ }
137
+ return self;
138
+ }
139
+
140
+ // A new image view, made with the view's first props after it's created or
141
+ // recycled (see updateProps), which sends its events through the component's
142
+ // event emitter: the ones JS has a handler for (see sendEvent:).
143
+ - (void)makeImageView
144
+ {
145
+ _imageView = [FFFastImageView new];
146
+ __weak __typeof(self) weakSelf = self;
147
+ _imageView.onFastImageLoadStart = ^(NSDictionary *event) {
148
+ [weakSelf sendEvent:FFFEventLoadStart type:"fastImageLoadStart" payload:event];
149
+ };
150
+ _imageView.onFastImageProgress = ^(NSDictionary *event) {
151
+ [weakSelf sendEvent:FFFEventProgress type:"fastImageProgress" payload:event];
152
+ };
153
+ _imageView.onFastImageLoad = ^(NSDictionary *event) {
154
+ [weakSelf sendEvent:FFFEventLoad type:"fastImageLoad" payload:event];
155
+ };
156
+ _imageView.onFastImageError = ^(NSDictionary *event) {
157
+ [weakSelf sendEvent:FFFEventError type:"fastImageError" payload:event];
158
+ };
159
+ _imageView.onFastImageLoadEnd = ^(NSDictionary *event) {
160
+ [weakSelf sendEvent:FFFEventLoadEnd type:"fastImageLoadEnd" payload:event];
161
+ };
162
+ _setsAllProps = YES;
163
+ self.contentView = _imageView;
164
+ _imageView.frame = RCTCGRectFromRect(_layoutMetrics.getPaddingFrame());
165
+ }
166
+
167
+ // Padding doesn't inset the image: it fills the view inside its borders (the
168
+ // padding box), as on Android. React Native lays the content view out inside
169
+ // the padding too; its clipping mask for an image view (the padding box's
170
+ // corners, in the image view's bounds) then fits it exactly.
171
+ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
172
+ oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics
173
+ {
174
+ [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
175
+ _imageView.frame = RCTCGRectFromRect(layoutMetrics.getPaddingFrame());
176
+ }
177
+
178
+ // The image view's event as it built it (not the generated event structs,
179
+ // which would add the fields an event doesn't have, e.g. width to an error's
180
+ // onLoadEnd), if JS has a handler for it as it happens: most images have
181
+ // none, and each event would be converted and dispatched to JS for nothing.
182
+ - (void)sendEvent:(FFFEvent)event type:(std::string)type payload:(NSDictionary *)payload
183
+ {
184
+ const auto &props = *std::static_pointer_cast<const FastImageViewProps>(_props);
185
+ if (_eventEmitter && (props.handledEvents & event)) {
186
+ _eventEmitter->dispatchEvent(type, FFFDynamicFromObject(payload ?: @{}));
187
+ }
188
+ }
189
+
190
+ // React Native sets the accessibility props on this view (its
191
+ // accessibilityElement), but RCTViewComponentView answers isAccessibilityElement
192
+ // with its content view's, which is NO for an image view: `accessible` did
193
+ // nothing. (React Native's Image makes its image view the accessibilityElement
194
+ // instead, which doesn't work here: a recycled view gets a new image view,
195
+ // without the props that didn't change.)
196
+ - (BOOL)isAccessibilityElement
197
+ {
198
+ return std::static_pointer_cast<const FastImageViewProps>(_props)->accessible;
199
+ }
200
+
201
+ - (void)prepareForRecycle
202
+ {
203
+ [super prepareForRecycle];
204
+ // A recycled view shows another image: it gets a new image view when it's
205
+ // used again (see updateProps), as a new view does, and has none while it
206
+ // waits in React Native's pool, where it may stay unused. The old one
207
+ // stops: removing it autoreleases it, and a load that finished just before
208
+ // can still reach it from the main queue after this view has its next
209
+ // element's event emitter.
210
+ [_imageView stop];
211
+ _imageView = nil;
212
+ self.contentView = nil;
213
+ // A fade from the old image view (see FFFastImageView's fadeIn:).
214
+ [self.layer removeAnimationForKey: kCATransition];
215
+ }
216
+
217
+ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps
218
+ {
219
+ if (!_imageView) {
220
+ [self makeImageView];
221
+ }
222
+ const auto &oldViewProps = *std::static_pointer_cast<const FastImageViewProps>(_props);
223
+ const auto &newViewProps = *std::static_pointer_cast<const FastImageViewProps>(props);
224
+ BOOL all = _setsAllProps;
225
+ _setsAllProps = NO;
226
+ FFFastImageView *view = _imageView;
227
+
228
+ if (all || oldViewProps.source != newViewProps.source) {
229
+ view.source = [RCTConvert FFFastImageSource:FFFJSON(newViewProps.source)];
230
+ }
231
+ if (all || oldViewProps.sources != newViewProps.sources) {
232
+ id sources = FFFJSON(newViewProps.sources);
233
+ view.sources = sources ? [RCTConvert FFFastImageSourceArray:sources] : nil;
234
+ }
235
+ if (all || oldViewProps.defaultSource != newViewProps.defaultSource) {
236
+ id defaultSource = FFFJSON(newViewProps.defaultSource);
237
+ view.defaultSource = defaultSource ? [RCTConvert UIImage:defaultSource] : nil;
238
+ }
239
+ if (all || oldViewProps.objectFit != newViewProps.objectFit) {
240
+ view.objectFit = [RCTConvert FFFObjectFit:FFFString(newViewProps.objectFit)];
241
+ }
242
+ if (all || oldViewProps.objectPositionX != newViewProps.objectPositionX) {
243
+ view.objectPositionX = newViewProps.objectPositionX;
244
+ }
245
+ if (all || oldViewProps.objectPositionXOffset != newViewProps.objectPositionXOffset) {
246
+ view.objectPositionXOffset = newViewProps.objectPositionXOffset;
247
+ }
248
+ if (all || oldViewProps.objectPositionY != newViewProps.objectPositionY) {
249
+ view.objectPositionY = newViewProps.objectPositionY;
250
+ }
251
+ if (all || oldViewProps.objectPositionYOffset != newViewProps.objectPositionYOffset) {
252
+ view.objectPositionYOffset = newViewProps.objectPositionYOffset;
253
+ }
254
+ if (all || oldViewProps.tintColor != newViewProps.tintColor) {
255
+ view.imageColor = RCTUIColorFromSharedColor(newViewProps.tintColor);
256
+ }
257
+ if (all || oldViewProps.recyclingKey != newViewProps.recyclingKey) {
258
+ // As it is, '' included: Codegen sends '' when it isn't set, and an
259
+ // empty key going to another one clears the image, as on Android.
260
+ view.recyclingKey = [NSString stringWithUTF8String:newViewProps.recyclingKey.c_str()];
261
+ }
262
+ if (all || oldViewProps.loopCount != newViewProps.loopCount) {
263
+ view.loopCount = newViewProps.loopCount;
264
+ }
265
+ if (all || oldViewProps.imageRendering != newViewProps.imageRendering) {
266
+ view.imageRendering = FFFString(newViewProps.imageRendering);
267
+ }
268
+ if (all || oldViewProps.paused != newViewProps.paused) {
269
+ view.paused = newViewProps.paused;
270
+ }
271
+ if (all || oldViewProps.transitionDuration != newViewProps.transitionDuration) {
272
+ view.transitionDuration = newViewProps.transitionDuration;
273
+ }
274
+ if (all || oldViewProps.transitionBetweenImages != newViewProps.transitionBetweenImages) {
275
+ view.transitionBetweenImages = newViewProps.transitionBetweenImages;
276
+ }
277
+ if (all || oldViewProps.transitionSkipOnCacheHit != newViewProps.transitionSkipOnCacheHit) {
278
+ view.transitionSkipOnCacheHit = FFFString(newViewProps.transitionSkipOnCacheHit);
279
+ }
280
+ if (all || oldViewProps.downsample != newViewProps.downsample) {
281
+ view.downsample = newViewProps.downsample;
282
+ }
283
+ if (all || oldViewProps.blurRadius != newViewProps.blurRadius) {
284
+ view.blurRadius = newViewProps.blurRadius;
285
+ }
286
+ if (all || oldViewProps.handledEvents != newViewProps.handledEvents) {
287
+ // Progress is tracked from the next load, as a handler added while
288
+ // loading was. (Each event is sent if it has a handler as it happens:
289
+ // see sendEvent:.)
290
+ view.trackProgress = (newViewProps.handledEvents & FFFEventProgress) != 0;
291
+ }
292
+ _propsChanged = YES;
293
+
294
+ [super updateProps:props oldProps:oldProps];
295
+ }
296
+
297
+ // Once the update's props and layout are all set: the image view loads (for
298
+ // its size, which it has by now).
299
+ - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask
300
+ {
301
+ [super finalizeUpdates:updateMask];
302
+ // RCTViewComponentView masks its image view subviews to the border radius
303
+ // while it clips (invalidateLayer), and leaves the mask when overflow
304
+ // becomes visible.
305
+ if (!std::static_pointer_cast<const FastImageViewProps>(_props)->getClipsContentToBounds()) {
306
+ _imageView.layer.mask = nil;
307
+ }
308
+ // Where objectPosition moved the image view, its mask moves back.
309
+ [_imageView updateMask];
310
+ if (_propsChanged) {
311
+ _propsChanged = NO;
312
+ [_imageView didSetProps];
313
+ }
314
+ }
315
+
316
+ // React Native makes the image view's mask again when the appearance changes
317
+ // (as after an update): where objectPosition moved the view, it moves back.
318
+ - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
319
+ {
320
+ [super traitCollectionDidChange:previousTraitCollection];
321
+ [_imageView updateMask];
322
+ }
323
+
324
+ @end
325
+
@@ -6,7 +6,7 @@
6
6
 
7
7
  @interface RCTConvert (FFFastImage)
8
8
 
9
- + (FFFResizeMode)FFFResizeMode:(id)json;
9
+ + (FFFObjectFit)FFFObjectFit:(id)json;
10
10
  + (FFFastImageSource *)FFFastImageSource:(id)json;
11
11
  + (NSArray<FFFastImageSource *> *)FFFastImageSourceArray:(id)json;
12
12
 
@@ -3,16 +3,13 @@
3
3
 
4
4
  @implementation RCTConvert (FFFastImage)
5
5
 
6
- RCT_ENUM_CONVERTER(FFFResizeMode, (@{
7
- @"cover": @(RCTResizeModeCover),
8
- @"contain": @(RCTResizeModeContain),
9
- @"stretch": @(RCTResizeModeStretch),
10
- @"center": @(RCTResizeModeCenter),
11
- // objectFit="scale-down": as center on iOS.
12
- @"scale-down": @(RCTResizeModeCenter),
13
- @"repeat": @(RCTResizeModeRepeat),
14
- @"none": @(FFFResizeModeNone),
15
- }), RCTResizeModeCover, integerValue);
6
+ RCT_ENUM_CONVERTER(FFFObjectFit, (@{
7
+ @"cover": @(FFFObjectFitCover),
8
+ @"contain": @(FFFObjectFitContain),
9
+ @"fill": @(FFFObjectFitFill),
10
+ @"scale-down": @(FFFObjectFitScaleDown),
11
+ @"none": @(FFFObjectFitNone),
12
+ }), FFFObjectFitCover, integerValue);
16
13
 
17
14
  RCT_ENUM_CONVERTER(FFFPriority, (@{
18
15
  @"low": @(FFFPriorityLow),
@@ -62,6 +59,8 @@ RCT_ENUM_CONVERTER(FFFCacheControl, (@{
62
59
  imageSource.cacheKey = cacheKey.length > 0 ? cacheKey : nil;
63
60
  id memoryCache = json[@"memoryCache"];
64
61
  imageSource.memoryCache = memoryCache && memoryCache != (id)kCFNull ? [self BOOL:memoryCache] : YES;
62
+ id diskCache = json[@"diskCache"];
63
+ imageSource.diskCache = diskCache && diskCache != (id)kCFNull ? [self BOOL:diskCache] : YES;
65
64
  CGFloat scale = json[@"scale"] && json[@"scale"] != (id)kCFNull ? [self CGFloat:json[@"scale"]] : 1;
66
65
  imageSource.pixelCount = [self CGFloat:json[@"width"]] * [self CGFloat:json[@"height"]] * scale * scale;
67
66
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-fast-image",
3
- "version": "9.3.7",
3
+ "version": "10.1.0",
4
4
  "description": "FastImage, performant React Native image component.",
5
5
  "keywords": [
6
6
  "cache",
@@ -21,7 +21,7 @@
21
21
  "author": "Dylan Vann <dylan@dylanvann.com> (https://dylanvann.com)",
22
22
  "main": "dist/index.cjs",
23
23
  "module": "dist/index",
24
- "react-native": "dist/index.cjs",
24
+ "react-native": "src/index",
25
25
  "browser": "dist/index.web.js",
26
26
  "typings": "dist/index.d.ts",
27
27
  "files": [
@@ -30,6 +30,9 @@
30
30
  "android/src/main",
31
31
  "ios/FastImage",
32
32
  "app.plugin.js",
33
+ "src",
34
+ "!src/**/*.test.tsx",
35
+ "!src/__snapshots__",
33
36
  "dist",
34
37
  "RNFastImage.podspec"
35
38
  ],
@@ -46,29 +49,45 @@
46
49
  },
47
50
  "packageManager": "bun@1.4.2",
48
51
  "resolutions": {
49
- "@types/react": "^17.0.14"
52
+ "@types/react": "^19.2.0"
50
53
  },
51
54
  "devDependencies": {
52
55
  "@semantic-release/changelog": "7.0.0",
53
56
  "@semantic-release/git": "11.0.1",
54
57
  "@types/bun": "^1.4.2",
55
- "@types/react": "^17.0.14",
56
- "@types/react-native": "^0.69.5",
57
- "@types/react-test-renderer": "^17.0.1",
58
+ "@types/react": "^19.2.0",
59
+ "@types/react-test-renderer": "^19.1.0",
58
60
  "conventional-changelog-angular": "8.3.1",
59
61
  "maestro-runner": "1.1.27",
60
62
  "odiff-bin": "^4.5.0",
61
63
  "oxfmt": "0.70.0",
62
64
  "oxlint": "1.85.0",
63
65
  "pretty-format": "^30.5.1",
64
- "react": "17.0.2",
65
- "react-test-renderer": "17.0.2",
66
+ "react": "19.2.0",
67
+ "react-native": "0.83.10",
68
+ "react-test-renderer": "19.2.0",
66
69
  "rolldown": "1.2.11",
67
70
  "semantic-release": "25.0.9",
68
71
  "typescript": "7.0.2"
69
72
  },
70
73
  "peerDependencies": {
71
- "react": "^17 || ^18 || ^19",
74
+ "react": "*",
72
75
  "react-native": "*"
76
+ },
77
+ "codegenConfig": {
78
+ "name": "RNFastImageSpec",
79
+ "type": "all",
80
+ "jsSrcsDir": "src/specs",
81
+ "android": {
82
+ "javaPackageName": "com.fastimage"
83
+ },
84
+ "ios": {
85
+ "componentProvider": {
86
+ "FastImageView": "FFFastImageViewComponentView"
87
+ },
88
+ "modulesProvider": {
89
+ "FastImageModule": "FFFastImageModule"
90
+ }
91
+ }
73
92
  }
74
93
  }
@@ -0,0 +1,28 @@
1
+ // FastImage.resizeMode, priority and cacheControl (deprecated), shared by the
2
+ // native (index.tsx) and web (index.web.tsx) versions.
3
+
4
+ // resizeMode was removed in 10.0 and is ignored (objectFit instead): its
5
+ // values are kept so code that reads them, e.g. FastImage.resizeMode.contain,
6
+ // doesn't throw.
7
+ export const resizeMode = {
8
+ contain: 'contain',
9
+ cover: 'cover',
10
+ stretch: 'stretch',
11
+ center: 'center',
12
+ repeat: 'repeat',
13
+ } as const
14
+
15
+ export const priority = {
16
+ low: 'low',
17
+ normal: 'normal',
18
+ high: 'high',
19
+ } as const
20
+
21
+ export const cacheControl = {
22
+ // Ignore headers, use uri as cache key, fetch only if not in cache.
23
+ immutable: 'immutable',
24
+ // Respect http headers, no aggressive caching.
25
+ web: 'web',
26
+ // Only load from cache.
27
+ cacheOnly: 'cacheOnly',
28
+ } as const
@@ -0,0 +1,180 @@
1
+ // @flow
2
+
3
+ import type { NativeSyntheticEvent, ViewProps } from 'react-native'
4
+
5
+ export type OnLoadEvent = NativeSyntheticEvent<
6
+ $ReadOnly<{
7
+ width: number,
8
+ height: number,
9
+ // The view's React tag (on iOS and Android; not on the web).
10
+ target?: number,
11
+ }>,
12
+ >
13
+
14
+ export type OnErrorEvent = NativeSyntheticEvent<
15
+ $ReadOnly<{|
16
+ error: string,
17
+ |}>,
18
+ >
19
+
20
+ export type OnProgressEvent = NativeSyntheticEvent<
21
+ $ReadOnly<{|
22
+ loaded: number,
23
+ total: number,
24
+ // loaded / total, from 0 to 1.
25
+ progress: number,
26
+ |}>,
27
+ >
28
+
29
+ export type Priority = $ReadOnly<{|
30
+ low: 'low',
31
+ normal: 'normal',
32
+ high: 'high',
33
+ |}>
34
+
35
+ export type ResizeMode = $ReadOnly<{|
36
+ contain: 'contain',
37
+ cover: 'cover',
38
+ stretch: 'stretch',
39
+ center: 'center',
40
+ repeat: 'repeat',
41
+ |}>
42
+
43
+ export type CacheControl = $ReadOnly<{|
44
+ immutable: 'immutable',
45
+ web: 'web',
46
+ cacheOnly: 'cacheOnly',
47
+ |}>
48
+
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
+ |}>
59
+ export type Priorities = $Values<Priority>
60
+ export type CacheControls = $Values<CacheControl>
61
+
62
+ export type LoadResult =
63
+ | {| ok: true, width: number, height: number |}
64
+ | {| ok: false, error: string |}
65
+
66
+ export type CacheLimits = {|
67
+ maxDiskSize?: ?number,
68
+ maxDiskAge?: ?number,
69
+ maxMemorySize?: ?number,
70
+ |}
71
+
72
+ export type CacheState = {|
73
+ maxDiskSize?: number,
74
+ maxDiskAge?: number,
75
+ maxMemorySize?: number,
76
+ diskSize?: number,
77
+ |}
78
+
79
+ export type CachePathResult =
80
+ | {| ok: true, path: string |}
81
+ | {| ok: false, error: string |}
82
+
83
+ export type ClearCacheResult = {| ok: true |} | {| ok: false, error: string |}
84
+
85
+ export type Transition = $ReadOnly<{|
86
+ duration?: ?number,
87
+ betweenImages?: ?boolean,
88
+ skipOnCacheHit?: ?('none' | 'memory' | 'all'),
89
+ |}>
90
+
91
+ export type FastImageDefaults = $ReadOnly<{|
92
+ transition?: ?(boolean | number | Transition),
93
+ |}>
94
+
95
+ export type PreloadSuccess = {|
96
+ uri: string,
97
+ ok: true,
98
+ width: number,
99
+ height: number,
100
+ |}
101
+
102
+ export type PreloadFailure = {|
103
+ uri?: string,
104
+ ok: false,
105
+ error: string,
106
+ |}
107
+
108
+ export type PreloadResult = PreloadSuccess | PreloadFailure
109
+
110
+ export type PreloadFn = (
111
+ sources: Array<FastImageSource>,
112
+ ) => Promise<Array<PreloadResult>>
113
+ export type FastImageSource = {
114
+ uri?: string,
115
+ headers?: Object,
116
+ priority?: Priorities,
117
+ cache?: CacheControls,
118
+ cacheKey?: string,
119
+ memoryCache?: boolean,
120
+ diskCache?: boolean,
121
+ width?: number,
122
+ height?: number,
123
+ scale?: number,
124
+ }
125
+
126
+ export type FastImageProps = $ReadOnly<{|
127
+ ...ViewProps,
128
+ onError?: ?(event: OnErrorEvent) => void,
129
+ onLoad?: ?(event: OnLoadEvent) => void,
130
+ onLoadEnd?: ?(result: LoadResult) => void,
131
+ onLoadStart?: ?() => void,
132
+ onProgress?: ?(event: OnProgressEvent) => void,
133
+
134
+ source?: ?(FastImageSource | Array<FastImageSource> | number),
135
+ defaultSource?: ?number,
136
+
137
+ tintColor?: number | string,
138
+ objectFit?: ?ObjectFit,
139
+ objectPosition?: ?ObjectPosition,
140
+ recyclingKey?: ?string,
141
+ loop?: ?(boolean | number),
142
+ imageRendering?: ?('auto' | 'smooth' | 'pixelated'),
143
+ paused?: ?boolean,
144
+ transition?: ?(boolean | number | Transition),
145
+ downsample?: ?boolean,
146
+ blurRadius?: ?number,
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",
151
+ |}>
152
+
153
+ export type FastImageBackgroundProps = $ReadOnly<{|
154
+ ...FastImageProps,
155
+ imageStyle?: $PropertyType<ViewProps, 'style'>,
156
+ imageRef?: React$Ref<any>,
157
+ children?: React$Node,
158
+ |}>
159
+
160
+ declare export var FastImageBackground: React$ComponentType<FastImageBackgroundProps>
161
+
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.
165
+ static resizeMode: ResizeMode;
166
+ // Deprecated: use the strings instead, e.g. priority: 'high'.
167
+ static priority: Priority;
168
+ // Deprecated: use the strings instead, e.g. cache: 'immutable'.
169
+ static cacheControl: CacheControl;
170
+ static preload: PreloadFn;
171
+ static clearMemoryCache: () => Promise<ClearCacheResult>;
172
+ static clearDiskCache: () => Promise<ClearCacheResult>;
173
+ static getCachePath: (source: FastImageSource) => Promise<CachePathResult>;
174
+ static configureCache: (limits?: CacheLimits) => Promise<CacheState>;
175
+ static setDefaults: (defaults: FastImageDefaults) => void;
176
+ static writeToCache: (
177
+ source: FastImageSource,
178
+ file: string,
179
+ ) => Promise<CachePathResult>;
180
+ }