react-native-fast-image 10.4.0 → 10.6.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.
@@ -44,9 +44,9 @@
44
44
  // downsample, or several sources: a load waits for the view's size (see
45
45
  // didSetProps).
46
46
  @property(nonatomic, assign) BOOL waitsForSize;
47
- // The `source` prop. With several `sources`, _source is the one picked for
48
- // the view's size instead.
49
- @property(nonatomic, strong) FFFastImageSource* propSource;
47
+ // The source that loads: the `source` prop's, or with several the one
48
+ // picked for the view's size.
49
+ @property(nonatomic, strong) FFFastImageSource* source;
50
50
  // Several sources: the next load switches to another one for a new view
51
51
  // size, and the one after it is loading. It's the same picture at another
52
52
  // size, so it doesn't fade in.
@@ -70,8 +70,18 @@
70
70
  // shownPlaceholder).
71
71
  @property(nonatomic, strong) UIImage* hashImage;
72
72
  @property(nonatomic, copy) NSString* hashImageKey;
73
- // Whether the view shows its placeholder (the placeholder prop or the
74
- // source's), and whether that's the source's (hashImage).
73
+ // placeholderSource's image once it has loaded, or nil: it shows instead of
74
+ // the other placeholders (see shownPlaceholder). Its load, and which it is.
75
+ @property(nonatomic, strong) UIImage* urlPlaceholderImage;
76
+ @property(nonatomic, strong) id<SDWebImageOperation> urlPlaceholderOperation;
77
+ @property(nonatomic, assign) NSUInteger urlPlaceholderLoad;
78
+ // placeholderSource changed: its load starts with the image's, or after the
79
+ // props if the image is still loading (see startUrlPlaceholderLoad).
80
+ @property(nonatomic, assign) BOOL needsUrlPlaceholderLoad;
81
+ // Whether the view shows a placeholder (the placeholder prop, the source's,
82
+ // or placeholderSource's), and whether it stands for the image (the source's
83
+ // or placeholderSource's): drawn as with contain for scale-down and none, as
84
+ // the image's size isn't known yet, scaled smoothly and not blurred.
75
85
  @property(nonatomic, assign) BOOL showsPlaceholder;
76
86
  @property(nonatomic, assign) BOOL showsHash;
77
87
  // dynamicRangeLimit switched between HDR and SDR: the image is decoded again,
@@ -444,7 +454,7 @@ static UIImage* FFFBlurredImage(UIImage* image, CGFloat scale, CGFloat radius, B
444
454
 
445
455
  - (void) setImage: (UIImage*)image {
446
456
  self.imageCount++;
447
- self.showsHash = image != nil && image == self.hashImage;
457
+ self.showsHash = image != nil && (image == self.hashImage || image == self.urlPlaceholderImage);
448
458
  self.showsPlaceholder = self.showsHash || (image != nil && image == _placeholder);
449
459
  if ([_imageRendering isEqualToString: @"pixelated"]) {
450
460
  // A source's placeholder is a blurred preview, scaled up smoothly
@@ -540,7 +550,7 @@ static UIImage* FFFBlurredImage(UIImage* image, CGFloat scale, CGFloat radius, B
540
550
  // Whether the image is blurred: a loaded image, not the placeholder prop (as
541
551
  // with React Native's Image, and on Android).
542
552
  - (BOOL) blurs: (UIImage*)image {
543
- return _blurRadius > 0 && image && image != _placeholder && image != self.hashImage;
553
+ return _blurRadius > 0 && image && image != _placeholder && image != self.hashImage && image != self.urlPlaceholderImage;
544
554
  }
545
555
 
546
556
  // Blurs the image off the main thread, and shows it (tinted as any image) unless
@@ -739,21 +749,11 @@ NSString *FFFErrorMessage(NSError *error)
739
749
  return event;
740
750
  }
741
751
 
742
- - (void) setSource: (FFFastImageSource*)source {
743
- if (self.propSource != source) {
744
- self.propSource = source;
745
- if (![self picksSource]) {
746
- _source = source;
747
- }
748
- _needsReload = YES;
749
- }
750
- }
751
-
752
752
  - (void) setSources: (NSArray<FFFastImageSource*>*)sources {
753
753
  if (_sources != sources) {
754
754
  _sources = [sources copy];
755
755
  if (![self picksSource]) {
756
- _source = self.propSource;
756
+ _source = _sources.firstObject;
757
757
  }
758
758
  _needsReload = YES;
759
759
  }
@@ -837,11 +837,16 @@ NSString *FFFErrorMessage(NSError *error)
837
837
  return [_dynamicRangeLimit isEqualToString: @"constrained"] || [_dynamicRangeLimit isEqualToString: @"no-limit"];
838
838
  }
839
839
 
840
+ // Shows at once, as a new source placeholder does (see updateHashImage),
841
+ // without loading the image again.
840
842
  - (void) setPlaceholder: (UIImage*)placeholder {
841
- if (_placeholder != placeholder) {
842
- _placeholder = placeholder;
843
- _needsReload = YES;
843
+ if (_placeholder == placeholder) {
844
+ return;
844
845
  }
846
+ UIImage* previous = [self shownPlaceholder];
847
+ BOOL showing = self.showsPlaceholder;
848
+ _placeholder = placeholder;
849
+ [self showChangedPlaceholder: previous showing: showing];
845
850
  }
846
851
 
847
852
  - (void) setSourcePlaceholders: (NSArray<NSString*>*)sourcePlaceholders {
@@ -849,20 +854,146 @@ NSString *FFFErrorMessage(NSError *error)
849
854
  [self updateHashImage];
850
855
  }
851
856
 
852
- // What shows while the image loads and if it fails: the picked source's
853
- // placeholder (its ThumbHash or blurDataUri), or the placeholder prop.
857
+ - (void) setPlaceholderHash: (NSString*)placeholderHash {
858
+ _placeholderHash = [placeholderHash copy];
859
+ [self updateHashImage];
860
+ }
861
+
862
+ // What shows while the image loads and if it fails: placeholderSource's
863
+ // image once it has loaded, the picked source's placeholder (its ThumbHash or
864
+ // blurDataUri), or the placeholder prop.
854
865
  - (UIImage*) shownPlaceholder {
855
- return self.hashImage ?: _placeholder;
866
+ return self.urlPlaceholderImage ?: self.hashImage ?: _placeholder;
867
+ }
868
+
869
+ // Shows the placeholder that shows now (shownPlaceholder) in place of
870
+ // `previous` if the view showed it, or if it showed nothing (one that arrived
871
+ // while nothing showed): never over a loaded image, or the image kept while
872
+ // a new source loads.
873
+ - (void) showChangedPlaceholder: (UIImage*)previous showing: (BOOL)showing {
874
+ UIImage* placeholder = [self shownPlaceholder];
875
+ if (placeholder == previous) {
876
+ return;
877
+ }
878
+ BOOL showsNothing = super.image == nil && !self.showsLoadedImage && !self.blursOverNothing;
879
+ if (showing || (placeholder && showsNothing)) {
880
+ [self setImage: placeholder];
881
+ }
882
+ }
883
+
884
+ // Images that views showed, by their source's cacheKey or url, while they're
885
+ // still in memory (held by a view or SDWebImage's memory cache), so
886
+ // placeholderSource finds one at once whatever size it was decoded at (the
887
+ // memory cache's key includes the size).
888
+ + (NSMapTable<NSString*, UIImage*>*) shownImages {
889
+ static NSMapTable* images;
890
+ static dispatch_once_t once;
891
+ dispatch_once(&once, ^{
892
+ images = [NSMapTable strongToWeakObjectsMapTable];
893
+ });
894
+ return images;
895
+ }
896
+
897
+ // The key a remote image (http or https) is recorded under: its cacheKey or
898
+ // url. nil for others (data uris, files), which aren't recorded.
899
+ + (NSString*) shownImageKey: (FFFastImageSource*)source {
900
+ NSString* scheme = source.url.scheme.lowercaseString;
901
+ if (![scheme isEqualToString: @"http"] && ![scheme isEqualToString: @"https"]) {
902
+ return nil;
903
+ }
904
+ return source.cacheKey.length > 0 ? source.cacheKey : source.url.absoluteString;
905
+ }
906
+
907
+ + (void) rememberShownImage: (UIImage*)image source: (FFFastImageSource*)source {
908
+ NSString* key = [self shownImageKey: source];
909
+ if (image && key) {
910
+ [[self shownImages] setObject: image forKey: key];
911
+ }
912
+ }
913
+
914
+ - (void) setPlaceholderSource: (FFFastImageSource*)placeholderSource {
915
+ if (!placeholderSource && !_placeholderSource) {
916
+ return;
917
+ }
918
+ _placeholderSource = placeholderSource;
919
+ [self cancelUrlPlaceholderLoad];
920
+ [self showUrlPlaceholderImage: nil];
921
+ self.needsUrlPlaceholderLoad = YES;
856
922
  }
857
923
 
858
- // The picked source's ThumbHash or blurDataUri, or nil.
924
+ - (void) cancelUrlPlaceholderLoad {
925
+ self.urlPlaceholderLoad++;
926
+ [self.urlPlaceholderOperation cancel];
927
+ self.urlPlaceholderOperation = nil;
928
+ }
929
+
930
+ // Loads placeholderSource's image with the image's load (after layout, so at
931
+ // the view's size, with the props applied), or after the image failed: not
932
+ // if the image shows at once (from the memory cache, or a data uri), or the
933
+ // placeholder is already loaded or loading.
934
+ - (void) startUrlPlaceholderLoad {
935
+ self.needsUrlPlaceholderLoad = NO;
936
+ if (!_placeholderSource.url || self.urlPlaceholderImage || self.urlPlaceholderOperation) {
937
+ return;
938
+ }
939
+ if (_source && !self.hasErrored && [self loadsDuringLayout]) {
940
+ return;
941
+ }
942
+ [self loadUrlPlaceholder];
943
+ }
944
+
945
+ // Loads placeholderSource's image, as a source would load (its cache,
946
+ // headers and cacheKey), at a high priority, as it only helps if it comes
947
+ // before the image. One a view still shows (or that's still in memory) shows
948
+ // at once. A failure shows nothing more.
949
+ - (void) loadUrlPlaceholder {
950
+ [self cancelUrlPlaceholderLoad];
951
+ NSUInteger load = self.urlPlaceholderLoad;
952
+ FFFastImageSource* source = _placeholderSource;
953
+ NSString* key = [FFFastImageView shownImageKey: source];
954
+ UIImage* shown = key ? [[FFFastImageView shownImages] objectForKey: key] : nil;
955
+ if (shown) {
956
+ [self showUrlPlaceholderImage: shown];
957
+ return;
958
+ }
959
+ SDWebImageOptions options = [source cacheOptions] | SDWebImageHighPriority | SDWebImageRetryFailed | SDWebImageHandleCookies;
960
+ SDWebImageContext* context = [self contextForSource: source box: [self decodeBox] cover: NO];
961
+ __weak typeof(self) weakSelf = self;
962
+ self.urlPlaceholderOperation = [[SDWebImageManager sharedManager] loadImageWithURL: source.url options: options context: context progress: nil completed: ^(UIImage* _Nullable image, NSData* _Nullable data, NSError* _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL* _Nullable imageURL) {
963
+ if (!finished || weakSelf.urlPlaceholderLoad != load) {
964
+ return;
965
+ }
966
+ weakSelf.urlPlaceholderOperation = nil;
967
+ if (!image) {
968
+ return;
969
+ }
970
+ [FFFastImageView rememberShownImage: image source: source];
971
+ [weakSelf showUrlPlaceholderImage: image];
972
+ }];
973
+ }
974
+
975
+ - (void) showUrlPlaceholderImage: (UIImage*)image {
976
+ if (self.urlPlaceholderImage == image) {
977
+ return;
978
+ }
979
+ UIImage* previous = [self shownPlaceholder];
980
+ BOOL showing = self.showsPlaceholder;
981
+ self.urlPlaceholderImage = image;
982
+ [self showChangedPlaceholder: previous showing: showing];
983
+ }
984
+
985
+ // The picked source's ThumbHash or blurDataUri, or placeholderHash, or nil.
859
986
  - (NSString*) pickedSourcePlaceholder {
860
987
  NSUInteger index = 0;
861
988
  if ([self picksSource]) {
862
989
  index = _source ? [_sources indexOfObjectIdenticalTo: _source] : NSNotFound;
990
+ // None until one is picked.
991
+ if (index == NSNotFound) {
992
+ return nil;
993
+ }
863
994
  }
864
995
  NSString* hash = index < _sourcePlaceholders.count ? _sourcePlaceholders[index] : nil;
865
- return hash.length > 0 ? hash : nil;
996
+ return hash.length > 0 ? hash : _placeholderHash.length > 0 ? _placeholderHash : nil;
866
997
  }
867
998
 
868
999
  // Decodes the picked source's placeholder. A view showing the previous
@@ -876,10 +1007,7 @@ NSString *FFFErrorMessage(NSError *error)
876
1007
  BOOL showing = self.showsPlaceholder;
877
1008
  self.hashImageKey = hash;
878
1009
  self.hashImage = [FFFThumbHash imageForPlaceholder: hash];
879
- UIImage* placeholder = [self shownPlaceholder];
880
- if (showing && placeholder != previous) {
881
- [self setImage: placeholder];
882
- }
1010
+ [self showChangedPlaceholder: previous showing: showing];
883
1011
  }
884
1012
 
885
1013
  - (void) didSetProps {
@@ -909,6 +1037,14 @@ NSString *FFFErrorMessage(NSError *error)
909
1037
  } else {
910
1038
  [self reloadIfResized];
911
1039
  }
1040
+ // A new placeholderSource while the image loads, or after it failed (a
1041
+ // load waiting for the view's size starts it with the image's).
1042
+ if (self.needsUrlPlaceholderLoad && !_needsReload && !self.waitsForSize) {
1043
+ if (!self.hasCompleted || self.hasErrored) {
1044
+ [self startUrlPlaceholderLoad];
1045
+ }
1046
+ self.needsUrlPlaceholderLoad = NO;
1047
+ }
912
1048
  }
913
1049
 
914
1050
  // The same image decoded again for a dynamicRangeLimit between HDR and SDR,
@@ -1003,6 +1139,7 @@ NSString *FFFErrorMessage(NSError *error)
1003
1139
  - (void) reloadImage {
1004
1140
  _needsReload = NO;
1005
1141
  self.needsDynamicRangeReload = NO;
1142
+ self.needsUrlPlaceholderLoad = NO;
1006
1143
  self.waitsForSize = NO;
1007
1144
  self.loadsSwitchedSource = self.switchesSource;
1008
1145
  self.switchesSource = NO;
@@ -1038,6 +1175,7 @@ NSString *FFFErrorMessage(NSError *error)
1038
1175
  [self setImage: [self shownPlaceholder]];
1039
1176
  self.showsLoadedImage = NO;
1040
1177
  [self sendOnError: @"Failed to decode the image"];
1178
+ [self startUrlPlaceholderLoad];
1041
1179
  if (self.onFastImageLoadEnd) {
1042
1180
  self.onFastImageLoadEnd([self loadEndEvent: NO]);
1043
1181
  }
@@ -1080,10 +1218,15 @@ NSString *FFFErrorMessage(NSError *error)
1080
1218
  self.retriedAfterBackground = NO;
1081
1219
  [self stopWaitingForActive];
1082
1220
 
1221
+ [self startUrlPlaceholderLoad];
1083
1222
  [self downloadImage: _source options: options context: [self loadContext] events: YES];
1084
- } else if ([self shownPlaceholder]) {
1085
- [self setImage: [self shownPlaceholder]];
1086
- self.showsLoadedImage = NO;
1223
+ } else {
1224
+ if ([self shownPlaceholder]) {
1225
+ [self setImage: [self shownPlaceholder]];
1226
+ self.showsLoadedImage = NO;
1227
+ }
1228
+ // No image: only placeholders show.
1229
+ [self startUrlPlaceholderLoad];
1087
1230
  }
1088
1231
  }
1089
1232
 
@@ -1319,6 +1462,8 @@ NSString *FFFErrorMessage(NSError *error)
1319
1462
  [weakSelf setImage: current];
1320
1463
  }
1321
1464
  weakSelf.showsLoadedImage = NO;
1465
+ // Shows instead of the other placeholders once it loads.
1466
+ [weakSelf startUrlPlaceholderLoad];
1322
1467
  [weakSelf sendOnError: [source errorMessage: error]];
1323
1468
  if (weakSelf.onFastImageLoadEnd) {
1324
1469
  weakSelf.onFastImageLoadEnd([weakSelf loadEndEvent: NO]);
@@ -1326,6 +1471,12 @@ NSString *FFFErrorMessage(NSError *error)
1326
1471
  } else {
1327
1472
  weakSelf.hasCompleted = YES;
1328
1473
  weakSelf.showsLoadedImage = YES;
1474
+ // For other views' placeholderSource.
1475
+ [FFFastImageView rememberShownImage: image source: source];
1476
+ // The image came first: its placeholder isn't needed.
1477
+ if (!weakSelf.urlPlaceholderImage) {
1478
+ [weakSelf cancelUrlPlaceholderLoad];
1479
+ }
1329
1480
  [weakSelf sendOnLoad: image];
1330
1481
  if (weakSelf.onFastImageLoadEnd) {
1331
1482
  weakSelf.onFastImageLoadEnd([weakSelf loadEndEvent: YES]);
@@ -1375,11 +1526,14 @@ NSString *FFFErrorMessage(NSError *error)
1375
1526
  self.waitsForSize = NO;
1376
1527
  [self stopWaitingForActive];
1377
1528
  [self sd_cancelLatestImageLoad];
1529
+ [self cancelUrlPlaceholderLoad];
1378
1530
  }
1379
1531
 
1380
1532
  - (void) dealloc {
1381
1533
  [self stopWaitingForActive];
1382
1534
  [self sd_cancelLatestImageLoad];
1535
+ // Fabric frees views it doesn't recycle without stop.
1536
+ [_urlPlaceholderOperation cancel];
1383
1537
  }
1384
1538
 
1385
1539
  @end
@@ -8,6 +8,7 @@
8
8
  #import <react/renderer/components/RNFastImageSpec/RCTComponentViewHelpers.h>
9
9
 
10
10
  #import "FFFastImageView.h"
11
+ #import "FFFThumbHash.h"
11
12
  #import "RCTConvert+FFFastImage.h"
12
13
 
13
14
  using namespace facebook::react;
@@ -102,6 +103,57 @@ static id _Nullable FFFJSON(const folly::dynamic &value)
102
103
  return value.isNull() ? nil : FFFObjectFromDynamic(value);
103
104
  }
104
105
 
106
+ // A source (or `placeholder`) without its thumbhash and blurDataUri, to
107
+ // compare: one source, or each of several.
108
+ static folly::dynamic FFFWithoutPlaceholders(const folly::dynamic &value)
109
+ {
110
+ if (value.isArray()) {
111
+ folly::dynamic result = folly::dynamic::array;
112
+ for (const auto &entry : value) {
113
+ result.push_back(FFFWithoutPlaceholders(entry));
114
+ }
115
+ return result;
116
+ }
117
+ if (!value.isObject()) {
118
+ return value;
119
+ }
120
+ folly::dynamic result = value;
121
+ result.erase("thumbhash");
122
+ result.erase("blurDataUri");
123
+ return result;
124
+ }
125
+
126
+ // A source's (or `placeholder`'s) ThumbHash, or its blurDataUri if it's a data
127
+ // uri (JS warns about another), or nil.
128
+ static NSString *_Nullable FFFSourcePlaceholder(NSDictionary *source)
129
+ {
130
+ id thumbhash = source[@"thumbhash"];
131
+ if ([thumbhash isKindOfClass:[NSString class]] && [thumbhash length] > 0) {
132
+ return thumbhash;
133
+ }
134
+ id blurDataUri = source[@"blurDataUri"];
135
+ if ([blurDataUri isKindOfClass:[NSString class]] && [FFFThumbHash isDataUri:blurDataUri]) {
136
+ return blurDataUri;
137
+ }
138
+ return nil;
139
+ }
140
+
141
+ // Whether the placeholder prop is a url to load apart from the image (a
142
+ // source with an http or https uri), rather than an image to show at once: a
143
+ // bundled image (served by the packager in development), a file or a data uri.
144
+ static BOOL FFFIsUrlPlaceholder(id _Nullable placeholder)
145
+ {
146
+ if (![placeholder isKindOfClass:[NSDictionary class]] || placeholder[@"__packager_asset"]) {
147
+ return NO;
148
+ }
149
+ id uri = placeholder[@"uri"];
150
+ if (![uri isKindOfClass:[NSString class]]) {
151
+ return NO;
152
+ }
153
+ NSString *scheme = [NSURL URLWithString:uri].scheme.lowercaseString;
154
+ return [scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"];
155
+ }
156
+
105
157
  // The events JS has a handler for: the handledEvents prop's bits (see
106
158
  // src/specs/FastImageViewNativeComponent.ts).
107
159
  typedef NS_OPTIONS(int32_t, FFFEvent) {
@@ -226,22 +278,35 @@ typedef NS_OPTIONS(int32_t, FFFEvent) {
226
278
  FFFastImageView *view = _imageView;
227
279
 
228
280
  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;
281
+ // One source, or several (an array). Only a change besides their
282
+ // thumbhashes and blurDataUris loads again: a new one for the same
283
+ // image (e.g. one that arrives later) shows at once.
284
+ BOOL loads = all || FFFWithoutPlaceholders(oldViewProps.source) != FFFWithoutPlaceholders(newViewProps.source);
285
+ id json = FFFJSON(newViewProps.source);
286
+ NSArray *entries = [json isKindOfClass:[NSArray class]] ? json : json ? @[ json ] : @[];
287
+ NSMutableArray<FFFastImageSource *> *sources = [NSMutableArray arrayWithCapacity:entries.count];
288
+ NSMutableArray<NSString *> *placeholders = [NSMutableArray arrayWithCapacity:entries.count];
289
+ for (id entry in entries) {
290
+ if ([entry isKindOfClass:[NSDictionary class]]) {
291
+ if (loads) {
292
+ [sources addObject:[RCTConvert FFFastImageSource:entry]];
293
+ }
294
+ [placeholders addObject:FFFSourcePlaceholder(entry) ?: @""];
295
+ }
296
+ }
297
+ if (loads) {
298
+ view.sources = sources.count > 0 ? sources : nil;
299
+ }
300
+ view.sourcePlaceholders = placeholders;
234
301
  }
235
302
  if (all || oldViewProps.placeholder != newViewProps.placeholder) {
303
+ // A thumbhash or blurDataUri, a url to load, or an image to show.
236
304
  id placeholder = FFFJSON(newViewProps.placeholder);
237
- view.placeholder = placeholder ? [RCTConvert UIImage:placeholder] : nil;
238
- }
239
- if (all || oldViewProps.sourcePlaceholders != newViewProps.sourcePlaceholders) {
240
- NSMutableArray<NSString *> *placeholders = [NSMutableArray arrayWithCapacity:newViewProps.sourcePlaceholders.size()];
241
- for (const auto &placeholder : newViewProps.sourcePlaceholders) {
242
- [placeholders addObject:[NSString stringWithUTF8String:placeholder.c_str()]];
243
- }
244
- view.sourcePlaceholders = placeholders.count > 0 ? placeholders : nil;
305
+ BOOL hash = [placeholder isKindOfClass:[NSDictionary class]] && (placeholder[@"thumbhash"] || placeholder[@"blurDataUri"]);
306
+ BOOL loads = !hash && FFFIsUrlPlaceholder(placeholder);
307
+ view.placeholderHash = hash ? FFFSourcePlaceholder(placeholder) : nil;
308
+ view.placeholder = placeholder && !hash && !loads ? [RCTConvert UIImage:placeholder] : nil;
309
+ view.placeholderSource = loads ? [RCTConvert FFFastImageSource:placeholder] : nil;
245
310
  }
246
311
  if (all || oldViewProps.objectFit != newViewProps.objectFit) {
247
312
  view.objectFit = [RCTConvert FFFObjectFit:FFFString(newViewProps.objectFit)];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-fast-image",
3
- "version": "10.4.0",
3
+ "version": "10.6.0",
4
4
  "description": "FastImage, performant React Native image component.",
5
5
  "keywords": [
6
6
  "cache",
package/src/index.js.flow CHANGED
@@ -110,6 +110,13 @@ export type PreloadResult = PreloadSuccess | PreloadFailure
110
110
  export type PreloadFn = (
111
111
  sources: Array<FastImageSource>,
112
112
  ) => Promise<Array<PreloadResult>>
113
+ export type PlaceholderSource = {
114
+ uri?: string,
115
+ headers?: Object,
116
+ cacheKey?: string,
117
+ cache?: CacheControls,
118
+ }
119
+
113
120
  export type SourcePlaceholder = {
114
121
  thumbhash?: string,
115
122
  blurDataUri?: string,
@@ -138,8 +145,8 @@ export type FastImageProps = $ReadOnly<{|
138
145
  onLoadStart?: ?() => void,
139
146
  onProgress?: ?(event: OnProgressEvent) => void,
140
147
 
141
- source?: ?(FastImageSource | Array<FastImageSource> | number),
142
- placeholder?: ?(number | string | SourcePlaceholder),
148
+ source?: ?(FastImageSource | Array<FastImageSource | number> | number),
149
+ placeholder?: ?(number | string | SourcePlaceholder | PlaceholderSource),
143
150
  // Deprecated: use placeholder, which is the same.
144
151
  defaultSource?: ?number,
145
152