react-native-nitro-image-pipeline 1.2.1 → 1.3.1
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 +75 -0
- package/lib/commonjs/PipelineImage.js +19 -4
- package/lib/commonjs/PipelineImage.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/PipelineImage.js +19 -4
- package/lib/module/PipelineImage.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/PipelineImage.d.ts +17 -1
- package/lib/typescript/src/PipelineImage.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/PipelineImage.tsx +88 -61
- package/src/index.ts +5 -1
package/README.md
CHANGED
|
@@ -71,6 +71,80 @@ so a style that already rounds the view rounds the bitmap too, with no separate
|
|
|
71
71
|
other prop (`resizeMode`, `recyclingKey`, `testID`, …) is passed straight through to
|
|
72
72
|
`NativeNitroImage`.
|
|
73
73
|
|
|
74
|
+
### Animating with `react-native-reanimated`
|
|
75
|
+
|
|
76
|
+
`<PipelineImage>` forwards its `ref` to the underlying `NativeNitroImage` host view, so it can be
|
|
77
|
+
passed straight to `Animated.createAnimatedComponent` — from
|
|
78
|
+
[react-native-reanimated](https://docs.swmansion.com/react-native-reanimated/) or React Native's
|
|
79
|
+
built-in `Animated`:
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import Animated, { FadeIn, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
|
|
83
|
+
import { PipelineImage } from 'react-native-nitro-image-pipeline';
|
|
84
|
+
|
|
85
|
+
const AnimatedPipelineImage = Animated.createAnimatedComponent(PipelineImage);
|
|
86
|
+
|
|
87
|
+
function Photo({ url }: { url: string }) {
|
|
88
|
+
const pressed = useSharedValue(false);
|
|
89
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
90
|
+
transform: [{ scale: withSpring(pressed.value ? 1.1 : 1) }],
|
|
91
|
+
}));
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<AnimatedPipelineImage
|
|
95
|
+
url={url}
|
|
96
|
+
entering={FadeIn}
|
|
97
|
+
style={[styles.photo, animatedStyle]}
|
|
98
|
+
onTouchStart={() => (pressed.value = true)}
|
|
99
|
+
onTouchEnd={() => (pressed.value = false)}
|
|
100
|
+
/>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const styles = StyleSheet.create({ photo: { width: 300, height: 200, borderRadius: 12 } });
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Layout animations (`entering`/`exiting`) work as on any animated component, and wrapping a plain
|
|
108
|
+
`<PipelineImage>` in an `Animated.View` is always an option if you'd rather not create one.
|
|
109
|
+
|
|
110
|
+
Because the pipeline bakes its processing into the bitmap at load time, the props fall into two
|
|
111
|
+
groups — view-layer properties that animate freely, and bitmap properties that don't:
|
|
112
|
+
|
|
113
|
+
- **`transform` and `opacity`** — the ideal case: they run entirely on the UI thread and never
|
|
114
|
+
touch the bitmap. Prefer a `scale` transform over animating `width`/`height`.
|
|
115
|
+
- **`width`/`height`** — the animation itself works (Reanimated drives the native view directly),
|
|
116
|
+
but the bitmap doesn't follow it. With numeric dimensions in `style` (including an animated
|
|
117
|
+
style's initial values) the bitmap is decoded once at that size and stretched by the view while
|
|
118
|
+
it animates; with flex/percent sizing the size comes from `onLayout`, which fires repeatedly
|
|
119
|
+
during the animation and requests a new variant each time. Animate a `scale` transform instead
|
|
120
|
+
and let the layout settle where it will.
|
|
121
|
+
- **`borderRadius`** — by default the component bakes `style`'s `borderRadius` into the bitmap;
|
|
122
|
+
an animated radius updates only the view layer, so the baked rounding wins and stays stale. To
|
|
123
|
+
animate rounding, opt out of baking with `cornerRadius={0}` and round at the view layer instead:
|
|
124
|
+
`overflow: 'hidden'` plus the animated `borderRadius`.
|
|
125
|
+
- **`blur`** — not animatable. It's a load-time bitmap operation behind an async native call, not
|
|
126
|
+
a view property, so a changing `blur` re-runs the pipeline per value — far too slow to drive
|
|
127
|
+
per-frame. To animate blurriness, render the sharp and blurred variants as two stacked
|
|
128
|
+
`<PipelineImage>`s and cross-fade the blurred one's `opacity` (both share the URL cache, so the
|
|
129
|
+
second variant loads from the same fetched source):
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
function BlurFade({ url, blurred }: { url: string; blurred: boolean }) {
|
|
133
|
+
const blurOpacity = useAnimatedStyle(() => ({
|
|
134
|
+
opacity: withTiming(blurred ? 1 : 0),
|
|
135
|
+
}));
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<View style={styles.photo}>
|
|
139
|
+
<PipelineImage url={url} style={StyleSheet.absoluteFill} />
|
|
140
|
+
<Animated.View style={[StyleSheet.absoluteFill, blurOpacity]}>
|
|
141
|
+
<PipelineImage url={url} blur={12} style={StyleSheet.absoluteFill} />
|
|
142
|
+
</Animated.View>
|
|
143
|
+
</View>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
74
148
|
### `useImage` hook
|
|
75
149
|
|
|
76
150
|
The simplest way to load an image in a component:
|
|
@@ -164,6 +238,7 @@ Loads an image from a URL and returns a `Promise<Image>`.
|
|
|
164
238
|
| `onLoad` | `(image: Image) => void` | — | Called when the image finishes loading |
|
|
165
239
|
| `onError` | `(error: Error) => void` | — | Called if loading fails |
|
|
166
240
|
| `onLayout` | `(event: LayoutChangeEvent) => void` | — | Standard `View` layout callback; also drives the deferred resize for non-numeric sizes |
|
|
241
|
+
| `ref` | `Ref<PipelineImageRef>` | — | Forwarded to the underlying `NativeNitroImage` host view — gives access to native-view methods (`measure`, …) and makes the component work with `Animated.createAnimatedComponent` (see [Animating](#animating-with-react-native-reanimated)) |
|
|
167
242
|
| `…NativeNitroImage props` | — | — | Everything else (`resizeMode`, `recyclingKey`, `testID`, …) is passed through to `NativeNitroImage` |
|
|
168
243
|
|
|
169
244
|
### `resizeForStyle(style)` / `resizeForLayout(width, height)`
|
|
@@ -3,13 +3,19 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.PipelineImage =
|
|
6
|
+
exports.PipelineImage = void 0;
|
|
7
7
|
var _react = require("react");
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
9
|
var _reactNativeNitroImage = require("react-native-nitro-image");
|
|
10
10
|
var _resizeForStyle = require("./resizeForStyle");
|
|
11
11
|
var _useImage = require("./useImage");
|
|
12
12
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
13
|
+
/**
|
|
14
|
+
* The instance `<PipelineImage>` exposes through its `ref` — the underlying
|
|
15
|
+
* `NativeNitroImage` host view, with the usual native-view methods
|
|
16
|
+
* (`measure`, …).
|
|
17
|
+
*/
|
|
18
|
+
|
|
13
19
|
function sameSize(a, b) {
|
|
14
20
|
return a?.width === b?.width && a?.height === b?.height;
|
|
15
21
|
}
|
|
@@ -37,6 +43,10 @@ function scaleRadius(cornerRadius, scale) {
|
|
|
37
43
|
* without flashing. Without an explicit `cornerRadius` prop, `style`'s
|
|
38
44
|
* `borderRadius`-family properties are baked into the bitmap instead — no
|
|
39
45
|
* separate view-layer rounding needed.
|
|
46
|
+
*
|
|
47
|
+
* The `ref` is forwarded to the underlying `NativeNitroImage` host view, so
|
|
48
|
+
* the component works with `Animated.createAnimatedComponent` (Reanimated or
|
|
49
|
+
* React Native's built-in `Animated`).
|
|
40
50
|
* @example
|
|
41
51
|
* ```tsx
|
|
42
52
|
* <PipelineImage
|
|
@@ -46,7 +56,7 @@ function scaleRadius(cornerRadius, scale) {
|
|
|
46
56
|
* />
|
|
47
57
|
* ```
|
|
48
58
|
*/
|
|
49
|
-
function PipelineImage({
|
|
59
|
+
const PipelineImage = exports.PipelineImage = /*#__PURE__*/(0, _react.forwardRef)(function PipelineImage({
|
|
50
60
|
url,
|
|
51
61
|
blur = 0,
|
|
52
62
|
cornerRadius,
|
|
@@ -56,7 +66,7 @@ function PipelineImage({
|
|
|
56
66
|
style,
|
|
57
67
|
onLayout,
|
|
58
68
|
...viewProps
|
|
59
|
-
}) {
|
|
69
|
+
}, ref) {
|
|
60
70
|
const scale = _reactNative.PixelRatio.get();
|
|
61
71
|
const styleSize = (0, _resizeForStyle.resizeForStyle)(style);
|
|
62
72
|
const [layoutSize, setLayoutSize] = (0, _react.useState)(undefined);
|
|
@@ -103,9 +113,14 @@ function PipelineImage({
|
|
|
103
113
|
};
|
|
104
114
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeNitroImage.NativeNitroImage, {
|
|
105
115
|
...viewProps,
|
|
116
|
+
ref: ref,
|
|
106
117
|
style: style,
|
|
107
118
|
onLayout: handleLayout,
|
|
108
119
|
image: image
|
|
109
120
|
});
|
|
110
|
-
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Reanimated and DevTools read the display name; the forwardRef wrapper
|
|
124
|
+
// would otherwise report as anonymous.
|
|
125
|
+
PipelineImage.displayName = 'PipelineImage';
|
|
111
126
|
//# sourceMappingURL=PipelineImage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","require","_reactNative","_reactNativeNitroImage","_resizeForStyle","_useImage","_jsxRuntime","sameSize","a","b","width","height","scaleRadius","cornerRadius","scale","topLeft","topRight","bottomLeft","bottomRight","PipelineImage","url","blur","cache","onLoad","onError","style","onLayout","viewProps","PixelRatio","get","styleSize","resizeForStyle","layoutSize","setLayoutSize","useState","undefined","resize","effectiveCornerRadius","cornerRadiusForStyle","image","error","useImage","enabled","onLoadRef","useRef","onErrorRef","useEffect","current","handleLayout","event","nativeEvent","layout","next","resizeForLayout","prev","jsx","NativeNitroImage"],"sourceRoot":"../../src","sources":["PipelineImage.tsx"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;
|
|
1
|
+
{"version":3,"names":["_react","require","_reactNative","_reactNativeNitroImage","_resizeForStyle","_useImage","_jsxRuntime","sameSize","a","b","width","height","scaleRadius","cornerRadius","scale","topLeft","topRight","bottomLeft","bottomRight","PipelineImage","exports","forwardRef","url","blur","cache","onLoad","onError","style","onLayout","viewProps","ref","PixelRatio","get","styleSize","resizeForStyle","layoutSize","setLayoutSize","useState","undefined","resize","effectiveCornerRadius","cornerRadiusForStyle","image","error","useImage","enabled","onLoadRef","useRef","onErrorRef","useEffect","current","handleLayout","event","nativeEvent","layout","next","resizeForLayout","prev","jsx","NativeNitroImage","displayName"],"sourceRoot":"../../src","sources":["PipelineImage.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_NitroImagePipeline","require","_PipelineImage","_resizeForStyle","_useImage"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,mBAAA,GAAAC,OAAA;AACA,IAAAC,cAAA,GAAAD,OAAA;
|
|
1
|
+
{"version":3,"names":["_NitroImagePipeline","require","_PipelineImage","_resizeForStyle","_useImage"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,mBAAA,GAAAC,OAAA;AACA,IAAAC,cAAA,GAAAD,OAAA;AAKA,IAAAE,eAAA,GAAAF,OAAA;AAWA,IAAAG,SAAA,GAAAH,OAAA","ignoreList":[]}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { forwardRef, useEffect, useRef, useState } from 'react';
|
|
4
4
|
import { PixelRatio } from 'react-native';
|
|
5
5
|
import { NativeNitroImage } from 'react-native-nitro-image';
|
|
6
6
|
import { cornerRadiusForStyle, resizeForLayout, resizeForStyle } from './resizeForStyle';
|
|
7
7
|
import { useImage } from './useImage';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The instance `<PipelineImage>` exposes through its `ref` — the underlying
|
|
11
|
+
* `NativeNitroImage` host view, with the usual native-view methods
|
|
12
|
+
* (`measure`, …).
|
|
13
|
+
*/
|
|
8
14
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
9
15
|
function sameSize(a, b) {
|
|
10
16
|
return a?.width === b?.width && a?.height === b?.height;
|
|
@@ -33,6 +39,10 @@ function scaleRadius(cornerRadius, scale) {
|
|
|
33
39
|
* without flashing. Without an explicit `cornerRadius` prop, `style`'s
|
|
34
40
|
* `borderRadius`-family properties are baked into the bitmap instead — no
|
|
35
41
|
* separate view-layer rounding needed.
|
|
42
|
+
*
|
|
43
|
+
* The `ref` is forwarded to the underlying `NativeNitroImage` host view, so
|
|
44
|
+
* the component works with `Animated.createAnimatedComponent` (Reanimated or
|
|
45
|
+
* React Native's built-in `Animated`).
|
|
36
46
|
* @example
|
|
37
47
|
* ```tsx
|
|
38
48
|
* <PipelineImage
|
|
@@ -42,7 +52,7 @@ function scaleRadius(cornerRadius, scale) {
|
|
|
42
52
|
* />
|
|
43
53
|
* ```
|
|
44
54
|
*/
|
|
45
|
-
export function PipelineImage({
|
|
55
|
+
export const PipelineImage = /*#__PURE__*/forwardRef(function PipelineImage({
|
|
46
56
|
url,
|
|
47
57
|
blur = 0,
|
|
48
58
|
cornerRadius,
|
|
@@ -52,7 +62,7 @@ export function PipelineImage({
|
|
|
52
62
|
style,
|
|
53
63
|
onLayout,
|
|
54
64
|
...viewProps
|
|
55
|
-
}) {
|
|
65
|
+
}, ref) {
|
|
56
66
|
const scale = PixelRatio.get();
|
|
57
67
|
const styleSize = resizeForStyle(style);
|
|
58
68
|
const [layoutSize, setLayoutSize] = useState(undefined);
|
|
@@ -99,9 +109,14 @@ export function PipelineImage({
|
|
|
99
109
|
};
|
|
100
110
|
return /*#__PURE__*/_jsx(NativeNitroImage, {
|
|
101
111
|
...viewProps,
|
|
112
|
+
ref: ref,
|
|
102
113
|
style: style,
|
|
103
114
|
onLayout: handleLayout,
|
|
104
115
|
image: image
|
|
105
116
|
});
|
|
106
|
-
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Reanimated and DevTools read the display name; the forwardRef wrapper
|
|
120
|
+
// would otherwise report as anonymous.
|
|
121
|
+
PipelineImage.displayName = 'PipelineImage';
|
|
107
122
|
//# sourceMappingURL=PipelineImage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["useEffect","useRef","useState","PixelRatio","NativeNitroImage","cornerRadiusForStyle","resizeForLayout","resizeForStyle","useImage","jsx","_jsx","sameSize","a","b","width","height","scaleRadius","cornerRadius","scale","topLeft","topRight","bottomLeft","bottomRight","PipelineImage","url","blur","cache","onLoad","onError","style","onLayout","viewProps","get","styleSize","layoutSize","setLayoutSize","undefined","resize","effectiveCornerRadius","image","error","enabled","onLoadRef","onErrorRef","current","handleLayout","event","nativeEvent","layout","next","prev"],"sourceRoot":"../../src","sources":["PipelineImage.tsx"],"mappings":";;AAAA,
|
|
1
|
+
{"version":3,"names":["forwardRef","useEffect","useRef","useState","PixelRatio","NativeNitroImage","cornerRadiusForStyle","resizeForLayout","resizeForStyle","useImage","jsx","_jsx","sameSize","a","b","width","height","scaleRadius","cornerRadius","scale","topLeft","topRight","bottomLeft","bottomRight","PipelineImage","url","blur","cache","onLoad","onError","style","onLayout","viewProps","ref","get","styleSize","layoutSize","setLayoutSize","undefined","resize","effectiveCornerRadius","image","error","enabled","onLoadRef","onErrorRef","current","handleLayout","event","nativeEvent","layout","next","prev","displayName"],"sourceRoot":"../../src","sources":["PipelineImage.tsx"],"mappings":";;AAAA,SAEEA,UAAU,EACVC,SAAS,EACTC,MAAM,EACNC,QAAQ,QACH,OAAO;AACd,SAGEC,UAAU,QACL,cAAc;AACrB,SAAqBC,gBAAgB,QAAQ,0BAA0B;AAEvE,SACEC,oBAAoB,EACpBC,eAAe,EACfC,cAAc,QACT,kBAAkB;AAMzB,SAASC,QAAQ,QAAQ,YAAY;;AAKrC;AACA;AACA;AACA;AACA;AAJA,SAAAC,GAAA,IAAAC,IAAA;AAoCA,SAASC,QAAQA,CAACC,CAAiB,EAAEC,CAAiB,EAAW;EAC/D,OAAOD,CAAC,EAAEE,KAAK,KAAKD,CAAC,EAAEC,KAAK,IAAIF,CAAC,EAAEG,MAAM,KAAKF,CAAC,EAAEE,MAAM;AACzD;AAEA,SAASC,WAAWA,CAClBC,YAAkC,EAClCC,KAAa,EACS;EACtB,IAAI,OAAOD,YAAY,KAAK,QAAQ,EAAE;IACpC,OAAOA,YAAY,GAAGC,KAAK;EAC7B;EACA,OAAO;IACLC,OAAO,EAAE,CAACF,YAAY,CAACE,OAAO,IAAI,CAAC,IAAID,KAAK;IAC5CE,QAAQ,EAAE,CAACH,YAAY,CAACG,QAAQ,IAAI,CAAC,IAAIF,KAAK;IAC9CG,UAAU,EAAE,CAACJ,YAAY,CAACI,UAAU,IAAI,CAAC,IAAIH,KAAK;IAClDI,WAAW,EAAE,CAACL,YAAY,CAACK,WAAW,IAAI,CAAC,IAAIJ;EACjD,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMK,aAAa,gBAAGxB,UAAU,CACrC,SAASwB,aAAaA,CACpB;EACEC,GAAG;EACHC,IAAI,GAAG,CAAC;EACRR,YAAY;EACZS,KAAK;EACLC,MAAM;EACNC,OAAO;EACPC,KAAK;EACLC,QAAQ;EACR,GAAGC;AACL,CAAC,EACDC,GAAG,EACH;EACA,MAAMd,KAAK,GAAGf,UAAU,CAAC8B,GAAG,CAAC,CAAC;EAC9B,MAAMC,SAAS,GAAG3B,cAAc,CAACsB,KAAK,CAAC;EACvC,MAAM,CAACM,UAAU,EAAEC,aAAa,CAAC,GAAGlC,QAAQ,CAC1CmC,SACF,CAAC;EACD;EACA;EACA,MAAMC,MAAM,GAAGJ,SAAS,IAAIC,UAAU;EACtC;EACA,MAAMI,qBAAqB,GACzBtB,YAAY,IAAIZ,oBAAoB,CAACwB,KAAK,CAAC,IAAI,CAAC;EAElD,MAAM;IAAEW,KAAK;IAAEC;EAAM,CAAC,GAAGjC,QAAQ,CAAC;IAChCgB,GAAG;IACHC,IAAI,EAAEA,IAAI,GAAGP,KAAK;IAClBD,YAAY,EAAED,WAAW,CAACuB,qBAAqB,EAAErB,KAAK,CAAC;IACvDQ,KAAK;IACLY,MAAM;IACNI,OAAO,EAAEJ,MAAM,KAAKD;EACtB,CAAC,CAAC;;EAEF;EACA,MAAMM,SAAS,GAAG1C,MAAM,CAAC0B,MAAM,CAAC;EAChC,MAAMiB,UAAU,GAAG3C,MAAM,CAAC2B,OAAO,CAAC;EAClC5B,SAAS,CAAC,MAAM;IACd2C,SAAS,CAACE,OAAO,GAAGlB,MAAM;IAC1BiB,UAAU,CAACC,OAAO,GAAGjB,OAAO;EAC9B,CAAC,CAAC;EACF5B,SAAS,CAAC,MAAM;IACd,IAAIwC,KAAK,EAAEG,SAAS,CAACE,OAAO,GAAGL,KAAK,CAAC;EACvC,CAAC,EAAE,CAACA,KAAK,CAAC,CAAC;EACXxC,SAAS,CAAC,MAAM;IACd,IAAIyC,KAAK,EAAEG,UAAU,CAACC,OAAO,GAAGJ,KAAK,CAAC;EACxC,CAAC,EAAE,CAACA,KAAK,CAAC,CAAC;EAEX,MAAMK,YAAY,GAAIC,KAAwB,IAAK;IACjDjB,QAAQ,GAAGiB,KAAK,CAAC;IACjB,MAAM;MAAEjC,KAAK;MAAEC;IAAO,CAAC,GAAGgC,KAAK,CAACC,WAAW,CAACC,MAAM;IAClD,MAAMC,IAAI,GAAG5C,eAAe,CAACQ,KAAK,EAAEC,MAAM,CAAC;IAC3C;IACA;IACAqB,aAAa,CAAEe,IAAI,IAAMxC,QAAQ,CAACwC,IAAI,EAAED,IAAI,CAAC,GAAGC,IAAI,GAAGD,IAAK,CAAC;EAC/D,CAAC;EAED,oBACExC,IAAA,CAACN,gBAAgB;IAAA,GACX2B,SAAS;IACbC,GAAG,EAAEA,GAAI;IACTH,KAAK,EAAEA,KAAM;IACbC,QAAQ,EAAEgB,YAAa;IACvBN,KAAK,EAAEA;EAAM,CACd,CAAC;AAEN,CACF,CAAC;;AAED;AACA;AACAjB,aAAa,CAAC6B,WAAW,GAAG,eAAe","ignoreList":[]}
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NitroImagePipeline","PipelineImage","cornerRadiusForStyle","resizeForLayout","resizeForStyle","useImage"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,kBAAkB,QAAQ,sBAAsB;AACzD,
|
|
1
|
+
{"version":3,"names":["NitroImagePipeline","PipelineImage","cornerRadiusForStyle","resizeForLayout","resizeForStyle","useImage"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,kBAAkB,QAAQ,sBAAsB;AACzD,SACEC,aAAa,QAGR,iBAAiB;AACxB,SACEC,oBAAoB,EACpBC,eAAe,EACfC,cAAc,QACT,kBAAkB;AAOzB,SAASC,QAAQ,QAAQ,YAAY","ignoreList":[]}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import { type ComponentRef } from 'react';
|
|
1
2
|
import { type HostComponent } from 'react-native';
|
|
2
3
|
import { type Image, NativeNitroImage } from 'react-native-nitro-image';
|
|
3
4
|
import type { CacheOption, CornerRadii } from './specs/nitro-image-toolkit.nitro';
|
|
4
5
|
type ReactProps<T> = T extends HostComponent<infer P> ? P : never;
|
|
5
6
|
type NativeImageProps = ReactProps<typeof NativeNitroImage>;
|
|
7
|
+
/**
|
|
8
|
+
* The instance `<PipelineImage>` exposes through its `ref` — the underlying
|
|
9
|
+
* `NativeNitroImage` host view, with the usual native-view methods
|
|
10
|
+
* (`measure`, …).
|
|
11
|
+
*/
|
|
12
|
+
export type PipelineImageRef = ComponentRef<typeof NativeNitroImage>;
|
|
6
13
|
export interface PipelineImageProps extends Omit<NativeImageProps, 'image'> {
|
|
7
14
|
/** URL of the image to load through the pipeline. */
|
|
8
15
|
url: string;
|
|
@@ -43,6 +50,10 @@ export interface PipelineImageProps extends Omit<NativeImageProps, 'image'> {
|
|
|
43
50
|
* without flashing. Without an explicit `cornerRadius` prop, `style`'s
|
|
44
51
|
* `borderRadius`-family properties are baked into the bitmap instead — no
|
|
45
52
|
* separate view-layer rounding needed.
|
|
53
|
+
*
|
|
54
|
+
* The `ref` is forwarded to the underlying `NativeNitroImage` host view, so
|
|
55
|
+
* the component works with `Animated.createAnimatedComponent` (Reanimated or
|
|
56
|
+
* React Native's built-in `Animated`).
|
|
46
57
|
* @example
|
|
47
58
|
* ```tsx
|
|
48
59
|
* <PipelineImage
|
|
@@ -52,6 +63,11 @@ export interface PipelineImageProps extends Omit<NativeImageProps, 'image'> {
|
|
|
52
63
|
* />
|
|
53
64
|
* ```
|
|
54
65
|
*/
|
|
55
|
-
export declare
|
|
66
|
+
export declare const PipelineImage: import("react").ForwardRefExoticComponent<PipelineImageProps & import("react").RefAttributes<import("react").Component<{
|
|
67
|
+
hybridRef?: import("react-native-nitro-modules").NitroViewWrappedCallback<((ref: import("react-native-nitro-modules").HybridView<import("react-native-nitro-image/lib/typescript/specs/ImageView.nitro").NativeNitroImageViewProps, import("react-native-nitro-image/lib/typescript/specs/ImageView.nitro").NativeNitroImageViewMethods>) => void) | undefined> | undefined;
|
|
68
|
+
image?: Image | import("react-native-nitro-image").ImageLoader;
|
|
69
|
+
resizeMode?: import("react-native-nitro-image/lib/typescript/specs/ImageView.nitro").ResizeMode;
|
|
70
|
+
recyclingKey?: string;
|
|
71
|
+
} & import("react-native").ViewProps, {}, any> & import("react-native").ReactNativeElement>>;
|
|
56
72
|
export {};
|
|
57
73
|
//# sourceMappingURL=PipelineImage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PipelineImage.d.ts","sourceRoot":"","sources":["../../../src/PipelineImage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PipelineImage.d.ts","sourceRoot":"","sources":["../../../src/PipelineImage.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EAKlB,MAAM,OAAO,CAAC;AACf,OAAO,EACL,KAAK,aAAa,EAGnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,KAAK,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAOxE,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EAEZ,MAAM,mCAAmC,CAAC;AAG3C,KAAK,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAClE,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE5D;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAErE,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACzE,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IACpC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAChC,iCAAiC;IACjC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,aAAa;;;;;4FAqEzB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { NitroImagePipeline } from './NitroImagePipeline';
|
|
2
|
-
export { PipelineImage, type PipelineImageProps } from './PipelineImage';
|
|
2
|
+
export { PipelineImage, type PipelineImageProps, type PipelineImageRef, } from './PipelineImage';
|
|
3
3
|
export { cornerRadiusForStyle, resizeForLayout, resizeForStyle, } from './resizeForStyle';
|
|
4
4
|
export type { CacheOption, CornerRadii, Options, ResizeOptions, } from './specs/nitro-image-toolkit.nitro';
|
|
5
5
|
export { useImage } from './useImage';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EACL,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,WAAW,EACX,WAAW,EACX,OAAO,EACP,aAAa,GACd,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-nitro-image-pipeline",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "High-performance image loading, caching, and processing for React Native, built with Nitro Modules",
|
|
5
5
|
"main": "./lib/commonjs/index.js",
|
|
6
6
|
"module": "./lib/module/index.js",
|
|
@@ -86,7 +86,8 @@
|
|
|
86
86
|
"react-native-nitro-image": "0.15.1"
|
|
87
87
|
},
|
|
88
88
|
"overrides": {
|
|
89
|
-
"lodash-es": "4.17.21"
|
|
89
|
+
"lodash-es": "4.17.21",
|
|
90
|
+
"typescript": "$typescript"
|
|
90
91
|
},
|
|
91
92
|
"react-native-builder-bob": {
|
|
92
93
|
"source": "src",
|
package/src/PipelineImage.tsx
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ComponentRef,
|
|
3
|
+
forwardRef,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react';
|
|
2
8
|
import {
|
|
3
9
|
type HostComponent,
|
|
4
10
|
type LayoutChangeEvent,
|
|
@@ -21,6 +27,13 @@ import { useImage } from './useImage';
|
|
|
21
27
|
type ReactProps<T> = T extends HostComponent<infer P> ? P : never;
|
|
22
28
|
type NativeImageProps = ReactProps<typeof NativeNitroImage>;
|
|
23
29
|
|
|
30
|
+
/**
|
|
31
|
+
* The instance `<PipelineImage>` exposes through its `ref` — the underlying
|
|
32
|
+
* `NativeNitroImage` host view, with the usual native-view methods
|
|
33
|
+
* (`measure`, …).
|
|
34
|
+
*/
|
|
35
|
+
export type PipelineImageRef = ComponentRef<typeof NativeNitroImage>;
|
|
36
|
+
|
|
24
37
|
export interface PipelineImageProps extends Omit<NativeImageProps, 'image'> {
|
|
25
38
|
/** URL of the image to load through the pipeline. */
|
|
26
39
|
url: string;
|
|
@@ -81,6 +94,10 @@ function scaleRadius(
|
|
|
81
94
|
* without flashing. Without an explicit `cornerRadius` prop, `style`'s
|
|
82
95
|
* `borderRadius`-family properties are baked into the bitmap instead — no
|
|
83
96
|
* separate view-layer rounding needed.
|
|
97
|
+
*
|
|
98
|
+
* The `ref` is forwarded to the underlying `NativeNitroImage` host view, so
|
|
99
|
+
* the component works with `Animated.createAnimatedComponent` (Reanimated or
|
|
100
|
+
* React Native's built-in `Animated`).
|
|
84
101
|
* @example
|
|
85
102
|
* ```tsx
|
|
86
103
|
* <PipelineImage
|
|
@@ -90,67 +107,77 @@ function scaleRadius(
|
|
|
90
107
|
* />
|
|
91
108
|
* ```
|
|
92
109
|
*/
|
|
93
|
-
export
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
export const PipelineImage = forwardRef<PipelineImageRef, PipelineImageProps>(
|
|
111
|
+
function PipelineImage(
|
|
112
|
+
{
|
|
113
|
+
url,
|
|
114
|
+
blur = 0,
|
|
115
|
+
cornerRadius,
|
|
116
|
+
cache,
|
|
117
|
+
onLoad,
|
|
118
|
+
onError,
|
|
119
|
+
style,
|
|
120
|
+
onLayout,
|
|
121
|
+
...viewProps
|
|
122
|
+
},
|
|
123
|
+
ref,
|
|
124
|
+
) {
|
|
125
|
+
const scale = PixelRatio.get();
|
|
126
|
+
const styleSize = resizeForStyle(style);
|
|
127
|
+
const [layoutSize, setLayoutSize] = useState<ResizeOptions | undefined>(
|
|
128
|
+
undefined,
|
|
129
|
+
);
|
|
130
|
+
// A numeric style is what the caller declared, so it wins and starts the
|
|
131
|
+
// request a frame earlier; the measured layout is the fallback.
|
|
132
|
+
const resize = styleSize ?? layoutSize;
|
|
133
|
+
// Same precedence: an explicit prop wins over what style implies.
|
|
134
|
+
const effectiveCornerRadius =
|
|
135
|
+
cornerRadius ?? cornerRadiusForStyle(style) ?? 0;
|
|
115
136
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
137
|
+
const { image, error } = useImage({
|
|
138
|
+
url,
|
|
139
|
+
blur: blur * scale,
|
|
140
|
+
cornerRadius: scaleRadius(effectiveCornerRadius, scale),
|
|
141
|
+
cache,
|
|
142
|
+
resize,
|
|
143
|
+
enabled: resize !== undefined,
|
|
144
|
+
});
|
|
124
145
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
146
|
+
// Latest callbacks in refs so inline arrow props don't re-fire the effects.
|
|
147
|
+
const onLoadRef = useRef(onLoad);
|
|
148
|
+
const onErrorRef = useRef(onError);
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
onLoadRef.current = onLoad;
|
|
151
|
+
onErrorRef.current = onError;
|
|
152
|
+
});
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
if (image) onLoadRef.current?.(image);
|
|
155
|
+
}, [image]);
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
if (error) onErrorRef.current?.(error);
|
|
158
|
+
}, [error]);
|
|
138
159
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
160
|
+
const handleLayout = (event: LayoutChangeEvent) => {
|
|
161
|
+
onLayout?.(event);
|
|
162
|
+
const { width, height } = event.nativeEvent.layout;
|
|
163
|
+
const next = resizeForLayout(width, height);
|
|
164
|
+
// Always record it (even when a numeric style is in charge) so a later
|
|
165
|
+
// switch to a non-numeric style has a size to fall back on.
|
|
166
|
+
setLayoutSize((prev) => (sameSize(prev, next) ? prev : next));
|
|
167
|
+
};
|
|
147
168
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
169
|
+
return (
|
|
170
|
+
<NativeNitroImage
|
|
171
|
+
{...viewProps}
|
|
172
|
+
ref={ref}
|
|
173
|
+
style={style}
|
|
174
|
+
onLayout={handleLayout}
|
|
175
|
+
image={image}
|
|
176
|
+
/>
|
|
177
|
+
);
|
|
178
|
+
},
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
// Reanimated and DevTools read the display name; the forwardRef wrapper
|
|
182
|
+
// would otherwise report as anonymous.
|
|
183
|
+
PipelineImage.displayName = 'PipelineImage';
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export { NitroImagePipeline } from './NitroImagePipeline';
|
|
2
|
-
export {
|
|
2
|
+
export {
|
|
3
|
+
PipelineImage,
|
|
4
|
+
type PipelineImageProps,
|
|
5
|
+
type PipelineImageRef,
|
|
6
|
+
} from './PipelineImage';
|
|
3
7
|
export {
|
|
4
8
|
cornerRadiusForStyle,
|
|
5
9
|
resizeForLayout,
|