react-native-skia-box-shadow 0.1.0 → 0.2.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 +56 -0
- package/lib/commonjs/AnimatedShadow.js +261 -0
- package/lib/commonjs/AnimatedShadow.js.map +1 -0
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/types.animated.js +6 -0
- package/lib/commonjs/types.animated.js.map +1 -0
- package/lib/module/AnimatedShadow.js +257 -0
- package/lib/module/AnimatedShadow.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.animated.js +4 -0
- package/lib/module/types.animated.js.map +1 -0
- package/lib/typescript/AnimatedShadow.d.ts +56 -0
- package/lib/typescript/AnimatedShadow.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/types.animated.d.ts +52 -0
- package/lib/typescript/types.animated.d.ts.map +1 -0
- package/package.json +14 -7
- package/src/AnimatedShadow.tsx +282 -0
- package/src/index.ts +6 -0
- package/src/types.animated.ts +54 -0
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ Powered by [`@shopify/react-native-skia`](https://shopify.github.io/react-native
|
|
|
12
12
|
- **Colors & Gradients** — solid colors or Skia shader fills (linear, radial, sweep)
|
|
13
13
|
- **Shapes** — rect, roundedRect, circle, or arbitrary SVG path
|
|
14
14
|
- **Multi-layer** — stack multiple shadow layers, just like in Figma
|
|
15
|
+
- **Animated** — 60fps animations via Reanimated SharedValues (optional)
|
|
15
16
|
- **Cross-platform** — iOS & Android
|
|
16
17
|
|
|
17
18
|
## Installation
|
|
@@ -21,6 +22,8 @@ npm install react-native-skia-box-shadow @shopify/react-native-skia
|
|
|
21
22
|
```
|
|
22
23
|
|
|
23
24
|
> **Peer dependency**: `@shopify/react-native-skia` >= 1.0.0
|
|
25
|
+
>
|
|
26
|
+
> For animated shadows: `react-native-reanimated` >= 3.0.0 (optional)
|
|
24
27
|
|
|
25
28
|
## Usage
|
|
26
29
|
|
|
@@ -43,6 +46,49 @@ import { Shadow } from 'react-native-skia-box-shadow';
|
|
|
43
46
|
</Shadow>
|
|
44
47
|
```
|
|
45
48
|
|
|
49
|
+
### Animated shadow
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { AnimatedShadow } from 'react-native-skia-box-shadow';
|
|
53
|
+
import { useSharedValue, withSpring } from 'react-native-reanimated';
|
|
54
|
+
|
|
55
|
+
const MyCard = () => {
|
|
56
|
+
const blur = useSharedValue(16);
|
|
57
|
+
const offsetY = useSharedValue(4);
|
|
58
|
+
const spread = useSharedValue(0);
|
|
59
|
+
|
|
60
|
+
const onPressIn = () => {
|
|
61
|
+
blur.value = withSpring(32);
|
|
62
|
+
offsetY.value = withSpring(12);
|
|
63
|
+
spread.value = withSpring(4);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const onPressOut = () => {
|
|
67
|
+
blur.value = withSpring(16);
|
|
68
|
+
offsetY.value = withSpring(4);
|
|
69
|
+
spread.value = withSpring(0);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<AnimatedShadow
|
|
74
|
+
shadows={{
|
|
75
|
+
fillStyle: { kind: 'color', color: 'rgba(0,0,0,0.15)' },
|
|
76
|
+
blurRadius: blur,
|
|
77
|
+
offsetY,
|
|
78
|
+
spread,
|
|
79
|
+
}}
|
|
80
|
+
shape={{ kind: 'roundedRect', radius: 16 }}
|
|
81
|
+
>
|
|
82
|
+
<Pressable onPressIn={onPressIn} onPressOut={onPressOut}>
|
|
83
|
+
<View style={styles.card}>
|
|
84
|
+
<Text>Press me</Text>
|
|
85
|
+
</View>
|
|
86
|
+
</Pressable>
|
|
87
|
+
</AnimatedShadow>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
```
|
|
91
|
+
|
|
46
92
|
### Multiple shadow layers
|
|
47
93
|
|
|
48
94
|
```tsx
|
|
@@ -142,6 +188,16 @@ The component renders a Skia `<Canvas>` behind your children. Each shadow layer
|
|
|
142
188
|
|
|
143
189
|
This is a React Native port of the Compose Multiplatform library [`vasyl-stetsiuk/shadow`](https://github.com/vasyl-stetsiuk/shadow).
|
|
144
190
|
|
|
191
|
+
## `<AnimatedShadow>`
|
|
192
|
+
|
|
193
|
+
Same API as `<Shadow>`, but numeric props (`blurRadius`, `spread`, `offsetX`, `offsetY`) accept Reanimated `SharedValue<number>` for 60fps UI-thread animations.
|
|
194
|
+
|
|
195
|
+
| Additional Prop | Type | Default | Description |
|
|
196
|
+
| -------------------- | -------- | ------- | ---------------------------------------------- |
|
|
197
|
+
| `maxCanvasPadding` | `number` | `120` | Max extent for animated values (prevents clip) |
|
|
198
|
+
|
|
199
|
+
Since animated values change at runtime, the canvas padding can't be auto-calculated. Set `maxCanvasPadding` to the largest extent your shadow can reach (blur × 3 + spread + offset).
|
|
200
|
+
|
|
145
201
|
## License
|
|
146
202
|
|
|
147
203
|
MIT © [Vasyl Stetsiuk](https://stetsiuk.dev)
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.AnimatedShadow = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _reactNativeSkia = require("@shopify/react-native-skia");
|
|
10
|
+
var _reactNativeReanimated = require("react-native-reanimated");
|
|
11
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
12
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
13
|
+
// ── Defaults ────────────────────────────────────────────────────
|
|
14
|
+
const DEFAULTS = {
|
|
15
|
+
fillStyle: {
|
|
16
|
+
kind: 'color',
|
|
17
|
+
color: 'rgba(0,0,0,0.10)'
|
|
18
|
+
},
|
|
19
|
+
blurRadius: 24,
|
|
20
|
+
spread: 4,
|
|
21
|
+
offsetX: 0,
|
|
22
|
+
offsetY: 0
|
|
23
|
+
};
|
|
24
|
+
const pixelRatio = _reactNative.PixelRatio.get();
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Read a value that may be static or a SharedValue.
|
|
28
|
+
* Called inside useDerivedValue / on UI thread.
|
|
29
|
+
*/
|
|
30
|
+
const readValue = (v, fallback) => {
|
|
31
|
+
'worklet';
|
|
32
|
+
|
|
33
|
+
if (typeof v === 'number') return v;
|
|
34
|
+
if (v === undefined || v === null) return fallback;
|
|
35
|
+
return v.value;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// ── Animated single shadow layer ────────────────────────────────
|
|
39
|
+
const AnimatedShadowLayer = ({
|
|
40
|
+
params,
|
|
41
|
+
width,
|
|
42
|
+
height,
|
|
43
|
+
defaultShape
|
|
44
|
+
}) => {
|
|
45
|
+
const {
|
|
46
|
+
fillStyle = DEFAULTS.fillStyle,
|
|
47
|
+
blurRadius = DEFAULTS.blurRadius,
|
|
48
|
+
spread = DEFAULTS.spread,
|
|
49
|
+
offsetX = DEFAULTS.offsetX,
|
|
50
|
+
offsetY = DEFAULTS.offsetY,
|
|
51
|
+
shape: shapeOverride
|
|
52
|
+
} = params;
|
|
53
|
+
const shape = shapeOverride ?? defaultShape;
|
|
54
|
+
|
|
55
|
+
// ── Paint (static — color changes don't need 60fps) ───────────
|
|
56
|
+
const paint = (0, _react.useMemo)(() => {
|
|
57
|
+
const p = _reactNativeSkia.Skia.Paint();
|
|
58
|
+
if (fillStyle.kind === 'color') {
|
|
59
|
+
p.setColor(_reactNativeSkia.Skia.Color(fillStyle.color));
|
|
60
|
+
} else {
|
|
61
|
+
p.setShader(fillStyle.factory(width, height));
|
|
62
|
+
}
|
|
63
|
+
return p;
|
|
64
|
+
}, [fillStyle, width, height]);
|
|
65
|
+
|
|
66
|
+
// ── Animated blur (derived on UI thread) ──────────────────────
|
|
67
|
+
const derivedBlur = (0, _reactNativeReanimated.useDerivedValue)(() => {
|
|
68
|
+
return readValue(blurRadius, DEFAULTS.blurRadius) / pixelRatio;
|
|
69
|
+
}, [blurRadius]);
|
|
70
|
+
|
|
71
|
+
// ── Animated offset transform ─────────────────────────────────
|
|
72
|
+
const offsetTransform = (0, _reactNativeReanimated.useDerivedValue)(() => {
|
|
73
|
+
return [{
|
|
74
|
+
translateX: readValue(offsetX, DEFAULTS.offsetX)
|
|
75
|
+
}, {
|
|
76
|
+
translateY: readValue(offsetY, DEFAULTS.offsetY)
|
|
77
|
+
}];
|
|
78
|
+
}, [offsetX, offsetY]);
|
|
79
|
+
|
|
80
|
+
// ── Animated spread transform ─────────────────────────────────
|
|
81
|
+
const scaleTransform = (0, _reactNativeReanimated.useDerivedValue)(() => {
|
|
82
|
+
const s = readValue(spread, DEFAULTS.spread);
|
|
83
|
+
const sw = width + s * 2;
|
|
84
|
+
const sh = height + s * 2;
|
|
85
|
+
return [{
|
|
86
|
+
scaleX: width > 0 ? sw / width : 1
|
|
87
|
+
}, {
|
|
88
|
+
scaleY: height > 0 ? sh / height : 1
|
|
89
|
+
}];
|
|
90
|
+
}, [spread, width, height]);
|
|
91
|
+
|
|
92
|
+
// ── Shape element ─────────────────────────────────────────────
|
|
93
|
+
const shapeElement = (0, _react.useMemo)(() => {
|
|
94
|
+
const blurChild = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSkia.Blur, {
|
|
95
|
+
blur: derivedBlur
|
|
96
|
+
});
|
|
97
|
+
switch (shape.kind) {
|
|
98
|
+
case 'roundedRect':
|
|
99
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSkia.RoundedRect, {
|
|
100
|
+
x: 0,
|
|
101
|
+
y: 0,
|
|
102
|
+
width: width,
|
|
103
|
+
height: height,
|
|
104
|
+
r: shape.radius,
|
|
105
|
+
paint: paint,
|
|
106
|
+
children: blurChild
|
|
107
|
+
});
|
|
108
|
+
case 'circle':
|
|
109
|
+
{
|
|
110
|
+
const r = Math.min(width, height) / 2;
|
|
111
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSkia.Circle, {
|
|
112
|
+
cx: width / 2,
|
|
113
|
+
cy: height / 2,
|
|
114
|
+
r: r,
|
|
115
|
+
paint: paint,
|
|
116
|
+
children: blurChild
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
case 'path':
|
|
120
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSkia.Path, {
|
|
121
|
+
path: shape.svgPath,
|
|
122
|
+
paint: paint,
|
|
123
|
+
children: blurChild
|
|
124
|
+
});
|
|
125
|
+
case 'rect':
|
|
126
|
+
default:
|
|
127
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSkia.Rect, {
|
|
128
|
+
x: 0,
|
|
129
|
+
y: 0,
|
|
130
|
+
width: width,
|
|
131
|
+
height: height,
|
|
132
|
+
paint: paint,
|
|
133
|
+
children: blurChild
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}, [shape, width, height, paint, derivedBlur]);
|
|
137
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSkia.Group, {
|
|
138
|
+
transform: offsetTransform,
|
|
139
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSkia.Group, {
|
|
140
|
+
transform: scaleTransform,
|
|
141
|
+
origin: {
|
|
142
|
+
x: width / 2,
|
|
143
|
+
y: height / 2
|
|
144
|
+
},
|
|
145
|
+
children: shapeElement
|
|
146
|
+
})
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* `<AnimatedShadow>` — Animated CSS-style box shadows.
|
|
152
|
+
*
|
|
153
|
+
* Same API as `<Shadow>`, but numeric props accept Reanimated
|
|
154
|
+
* `SharedValue<number>` for 60fps animations on the UI thread.
|
|
155
|
+
*
|
|
156
|
+
* Requires `react-native-reanimated` >= 3.0.0.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```tsx
|
|
160
|
+
* import { AnimatedShadow } from 'react-native-skia-box-shadow';
|
|
161
|
+
* import { useSharedValue, withSpring } from 'react-native-reanimated';
|
|
162
|
+
*
|
|
163
|
+
* const MyCard = () => {
|
|
164
|
+
* const blur = useSharedValue(16);
|
|
165
|
+
* const offsetY = useSharedValue(4);
|
|
166
|
+
* const spread = useSharedValue(0);
|
|
167
|
+
*
|
|
168
|
+
* const onPressIn = () => {
|
|
169
|
+
* blur.value = withSpring(32);
|
|
170
|
+
* offsetY.value = withSpring(12);
|
|
171
|
+
* spread.value = withSpring(4);
|
|
172
|
+
* };
|
|
173
|
+
*
|
|
174
|
+
* const onPressOut = () => {
|
|
175
|
+
* blur.value = withSpring(16);
|
|
176
|
+
* offsetY.value = withSpring(4);
|
|
177
|
+
* spread.value = withSpring(0);
|
|
178
|
+
* };
|
|
179
|
+
*
|
|
180
|
+
* return (
|
|
181
|
+
* <AnimatedShadow
|
|
182
|
+
* shadows={{
|
|
183
|
+
* fillStyle: { kind: 'color', color: 'rgba(0,0,0,0.15)' },
|
|
184
|
+
* blurRadius: blur,
|
|
185
|
+
* offsetY,
|
|
186
|
+
* spread,
|
|
187
|
+
* }}
|
|
188
|
+
* shape={{ kind: 'roundedRect', radius: 16 }}
|
|
189
|
+
* >
|
|
190
|
+
* <Pressable onPressIn={onPressIn} onPressOut={onPressOut}>
|
|
191
|
+
* <View style={styles.card}>
|
|
192
|
+
* <Text>Press me</Text>
|
|
193
|
+
* </View>
|
|
194
|
+
* </Pressable>
|
|
195
|
+
* </AnimatedShadow>
|
|
196
|
+
* );
|
|
197
|
+
* };
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
const AnimatedShadow = ({
|
|
201
|
+
shadows,
|
|
202
|
+
shape = {
|
|
203
|
+
kind: 'rect'
|
|
204
|
+
},
|
|
205
|
+
width: _width,
|
|
206
|
+
height: _height,
|
|
207
|
+
maxCanvasPadding = 120,
|
|
208
|
+
style,
|
|
209
|
+
children
|
|
210
|
+
}) => {
|
|
211
|
+
const [layout, setLayout] = (0, _react.useState)(null);
|
|
212
|
+
const onLayout = e => {
|
|
213
|
+
const {
|
|
214
|
+
width,
|
|
215
|
+
height
|
|
216
|
+
} = e.nativeEvent.layout;
|
|
217
|
+
setLayout({
|
|
218
|
+
width,
|
|
219
|
+
height
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
const width = _width ?? layout?.width ?? 0;
|
|
223
|
+
const height = _height ?? layout?.height ?? 0;
|
|
224
|
+
const shadowList = Array.isArray(shadows) ? shadows : [shadows];
|
|
225
|
+
const hasSize = width > 0 && height > 0;
|
|
226
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
227
|
+
style: [styles.container, style],
|
|
228
|
+
onLayout: onLayout,
|
|
229
|
+
children: [hasSize && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSkia.Canvas, {
|
|
230
|
+
style: [styles.canvas, {
|
|
231
|
+
top: -maxCanvasPadding,
|
|
232
|
+
left: -maxCanvasPadding,
|
|
233
|
+
width: width + maxCanvasPadding * 2,
|
|
234
|
+
height: height + maxCanvasPadding * 2
|
|
235
|
+
}],
|
|
236
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSkia.Group, {
|
|
237
|
+
transform: [{
|
|
238
|
+
translateX: maxCanvasPadding
|
|
239
|
+
}, {
|
|
240
|
+
translateY: maxCanvasPadding
|
|
241
|
+
}],
|
|
242
|
+
children: shadowList.map((params, idx) => /*#__PURE__*/(0, _jsxRuntime.jsx)(AnimatedShadowLayer, {
|
|
243
|
+
params: params,
|
|
244
|
+
width: width,
|
|
245
|
+
height: height,
|
|
246
|
+
defaultShape: shape
|
|
247
|
+
}, idx))
|
|
248
|
+
})
|
|
249
|
+
}), children]
|
|
250
|
+
});
|
|
251
|
+
};
|
|
252
|
+
exports.AnimatedShadow = AnimatedShadow;
|
|
253
|
+
const styles = _reactNative.StyleSheet.create({
|
|
254
|
+
container: {},
|
|
255
|
+
canvas: {
|
|
256
|
+
position: 'absolute',
|
|
257
|
+
pointerEvents: 'none'
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
var _default = exports.default = AnimatedShadow;
|
|
261
|
+
//# sourceMappingURL=AnimatedShadow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_reactNativeSkia","_reactNativeReanimated","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","DEFAULTS","fillStyle","kind","color","blurRadius","spread","offsetX","offsetY","pixelRatio","PixelRatio","readValue","v","fallback","undefined","value","AnimatedShadowLayer","params","width","height","defaultShape","shape","shapeOverride","paint","useMemo","p","Skia","Paint","setColor","Color","setShader","factory","derivedBlur","useDerivedValue","offsetTransform","translateX","translateY","scaleTransform","s","sw","sh","scaleX","scaleY","shapeElement","blurChild","jsx","Blur","blur","RoundedRect","x","y","radius","children","Math","min","Circle","cx","cy","Path","path","svgPath","Rect","Group","transform","origin","AnimatedShadow","shadows","_width","_height","maxCanvasPadding","style","layout","setLayout","useState","onLayout","nativeEvent","shadowList","Array","isArray","hasSize","jsxs","View","styles","container","Canvas","canvas","top","left","map","idx","exports","StyleSheet","create","position","pointerEvents","_default"],"sourceRoot":"../../src","sources":["AnimatedShadow.tsx"],"mappings":"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","ignoreList":[]}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
Object.defineProperty(exports, "AnimatedShadow", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _AnimatedShadow.AnimatedShadow;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
6
12
|
Object.defineProperty(exports, "Shadow", {
|
|
7
13
|
enumerable: true,
|
|
8
14
|
get: function () {
|
|
@@ -22,5 +28,6 @@ Object.defineProperty(exports, "ShadowView", {
|
|
|
22
28
|
}
|
|
23
29
|
});
|
|
24
30
|
var _Shadow = _interopRequireWildcard(require("./Shadow"));
|
|
31
|
+
var _AnimatedShadow = require("./AnimatedShadow");
|
|
25
32
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
26
33
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_Shadow","_interopRequireWildcard","require","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"names":["_Shadow","_interopRequireWildcard","require","_AnimatedShadow","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,OAAA,GAAAC,uBAAA,CAAAC,OAAA;AACA,IAAAC,eAAA,GAAAD,OAAA;AAAkD,SAAAD,wBAAAG,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAL,uBAAA,YAAAA,CAAAG,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAC,OAAA,EAAAV,CAAA,iBAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAK,GAAA,CAAAX,CAAA,UAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,GAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,EAAAQ,CAAA,gBAAAP,CAAA,IAAAD,CAAA,gBAAAC,CAAA,OAAAa,cAAA,CAAAC,IAAA,CAAAf,CAAA,EAAAC,CAAA,OAAAM,CAAA,IAAAD,CAAA,GAAAU,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAlB,CAAA,EAAAC,CAAA,OAAAM,CAAA,CAAAK,GAAA,IAAAL,CAAA,CAAAM,GAAA,IAAAP,CAAA,CAAAE,CAAA,EAAAP,CAAA,EAAAM,CAAA,IAAAC,CAAA,CAAAP,CAAA,IAAAD,CAAA,CAAAC,CAAA,WAAAO,CAAA,KAAAR,CAAA,EAAAC,CAAA","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["types.animated.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React, { useMemo, useState } from 'react';
|
|
4
|
+
import { StyleSheet, View, PixelRatio } from 'react-native';
|
|
5
|
+
import { Canvas, Group, RoundedRect, Rect, Circle, Path, Blur, Skia } from '@shopify/react-native-skia';
|
|
6
|
+
import { useDerivedValue } from "react-native-reanimated";
|
|
7
|
+
|
|
8
|
+
// ── Defaults ────────────────────────────────────────────────────
|
|
9
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
|
+
const DEFAULTS = {
|
|
11
|
+
fillStyle: {
|
|
12
|
+
kind: 'color',
|
|
13
|
+
color: 'rgba(0,0,0,0.10)'
|
|
14
|
+
},
|
|
15
|
+
blurRadius: 24,
|
|
16
|
+
spread: 4,
|
|
17
|
+
offsetX: 0,
|
|
18
|
+
offsetY: 0
|
|
19
|
+
};
|
|
20
|
+
const pixelRatio = PixelRatio.get();
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Read a value that may be static or a SharedValue.
|
|
24
|
+
* Called inside useDerivedValue / on UI thread.
|
|
25
|
+
*/
|
|
26
|
+
const readValue = (v, fallback) => {
|
|
27
|
+
'worklet';
|
|
28
|
+
|
|
29
|
+
if (typeof v === 'number') return v;
|
|
30
|
+
if (v === undefined || v === null) return fallback;
|
|
31
|
+
return v.value;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// ── Animated single shadow layer ────────────────────────────────
|
|
35
|
+
const AnimatedShadowLayer = ({
|
|
36
|
+
params,
|
|
37
|
+
width,
|
|
38
|
+
height,
|
|
39
|
+
defaultShape
|
|
40
|
+
}) => {
|
|
41
|
+
const {
|
|
42
|
+
fillStyle = DEFAULTS.fillStyle,
|
|
43
|
+
blurRadius = DEFAULTS.blurRadius,
|
|
44
|
+
spread = DEFAULTS.spread,
|
|
45
|
+
offsetX = DEFAULTS.offsetX,
|
|
46
|
+
offsetY = DEFAULTS.offsetY,
|
|
47
|
+
shape: shapeOverride
|
|
48
|
+
} = params;
|
|
49
|
+
const shape = shapeOverride ?? defaultShape;
|
|
50
|
+
|
|
51
|
+
// ── Paint (static — color changes don't need 60fps) ───────────
|
|
52
|
+
const paint = useMemo(() => {
|
|
53
|
+
const p = Skia.Paint();
|
|
54
|
+
if (fillStyle.kind === 'color') {
|
|
55
|
+
p.setColor(Skia.Color(fillStyle.color));
|
|
56
|
+
} else {
|
|
57
|
+
p.setShader(fillStyle.factory(width, height));
|
|
58
|
+
}
|
|
59
|
+
return p;
|
|
60
|
+
}, [fillStyle, width, height]);
|
|
61
|
+
|
|
62
|
+
// ── Animated blur (derived on UI thread) ──────────────────────
|
|
63
|
+
const derivedBlur = useDerivedValue(() => {
|
|
64
|
+
return readValue(blurRadius, DEFAULTS.blurRadius) / pixelRatio;
|
|
65
|
+
}, [blurRadius]);
|
|
66
|
+
|
|
67
|
+
// ── Animated offset transform ─────────────────────────────────
|
|
68
|
+
const offsetTransform = useDerivedValue(() => {
|
|
69
|
+
return [{
|
|
70
|
+
translateX: readValue(offsetX, DEFAULTS.offsetX)
|
|
71
|
+
}, {
|
|
72
|
+
translateY: readValue(offsetY, DEFAULTS.offsetY)
|
|
73
|
+
}];
|
|
74
|
+
}, [offsetX, offsetY]);
|
|
75
|
+
|
|
76
|
+
// ── Animated spread transform ─────────────────────────────────
|
|
77
|
+
const scaleTransform = useDerivedValue(() => {
|
|
78
|
+
const s = readValue(spread, DEFAULTS.spread);
|
|
79
|
+
const sw = width + s * 2;
|
|
80
|
+
const sh = height + s * 2;
|
|
81
|
+
return [{
|
|
82
|
+
scaleX: width > 0 ? sw / width : 1
|
|
83
|
+
}, {
|
|
84
|
+
scaleY: height > 0 ? sh / height : 1
|
|
85
|
+
}];
|
|
86
|
+
}, [spread, width, height]);
|
|
87
|
+
|
|
88
|
+
// ── Shape element ─────────────────────────────────────────────
|
|
89
|
+
const shapeElement = useMemo(() => {
|
|
90
|
+
const blurChild = /*#__PURE__*/_jsx(Blur, {
|
|
91
|
+
blur: derivedBlur
|
|
92
|
+
});
|
|
93
|
+
switch (shape.kind) {
|
|
94
|
+
case 'roundedRect':
|
|
95
|
+
return /*#__PURE__*/_jsx(RoundedRect, {
|
|
96
|
+
x: 0,
|
|
97
|
+
y: 0,
|
|
98
|
+
width: width,
|
|
99
|
+
height: height,
|
|
100
|
+
r: shape.radius,
|
|
101
|
+
paint: paint,
|
|
102
|
+
children: blurChild
|
|
103
|
+
});
|
|
104
|
+
case 'circle':
|
|
105
|
+
{
|
|
106
|
+
const r = Math.min(width, height) / 2;
|
|
107
|
+
return /*#__PURE__*/_jsx(Circle, {
|
|
108
|
+
cx: width / 2,
|
|
109
|
+
cy: height / 2,
|
|
110
|
+
r: r,
|
|
111
|
+
paint: paint,
|
|
112
|
+
children: blurChild
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
case 'path':
|
|
116
|
+
return /*#__PURE__*/_jsx(Path, {
|
|
117
|
+
path: shape.svgPath,
|
|
118
|
+
paint: paint,
|
|
119
|
+
children: blurChild
|
|
120
|
+
});
|
|
121
|
+
case 'rect':
|
|
122
|
+
default:
|
|
123
|
+
return /*#__PURE__*/_jsx(Rect, {
|
|
124
|
+
x: 0,
|
|
125
|
+
y: 0,
|
|
126
|
+
width: width,
|
|
127
|
+
height: height,
|
|
128
|
+
paint: paint,
|
|
129
|
+
children: blurChild
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}, [shape, width, height, paint, derivedBlur]);
|
|
133
|
+
return /*#__PURE__*/_jsx(Group, {
|
|
134
|
+
transform: offsetTransform,
|
|
135
|
+
children: /*#__PURE__*/_jsx(Group, {
|
|
136
|
+
transform: scaleTransform,
|
|
137
|
+
origin: {
|
|
138
|
+
x: width / 2,
|
|
139
|
+
y: height / 2
|
|
140
|
+
},
|
|
141
|
+
children: shapeElement
|
|
142
|
+
})
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* `<AnimatedShadow>` — Animated CSS-style box shadows.
|
|
148
|
+
*
|
|
149
|
+
* Same API as `<Shadow>`, but numeric props accept Reanimated
|
|
150
|
+
* `SharedValue<number>` for 60fps animations on the UI thread.
|
|
151
|
+
*
|
|
152
|
+
* Requires `react-native-reanimated` >= 3.0.0.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```tsx
|
|
156
|
+
* import { AnimatedShadow } from 'react-native-skia-box-shadow';
|
|
157
|
+
* import { useSharedValue, withSpring } from 'react-native-reanimated';
|
|
158
|
+
*
|
|
159
|
+
* const MyCard = () => {
|
|
160
|
+
* const blur = useSharedValue(16);
|
|
161
|
+
* const offsetY = useSharedValue(4);
|
|
162
|
+
* const spread = useSharedValue(0);
|
|
163
|
+
*
|
|
164
|
+
* const onPressIn = () => {
|
|
165
|
+
* blur.value = withSpring(32);
|
|
166
|
+
* offsetY.value = withSpring(12);
|
|
167
|
+
* spread.value = withSpring(4);
|
|
168
|
+
* };
|
|
169
|
+
*
|
|
170
|
+
* const onPressOut = () => {
|
|
171
|
+
* blur.value = withSpring(16);
|
|
172
|
+
* offsetY.value = withSpring(4);
|
|
173
|
+
* spread.value = withSpring(0);
|
|
174
|
+
* };
|
|
175
|
+
*
|
|
176
|
+
* return (
|
|
177
|
+
* <AnimatedShadow
|
|
178
|
+
* shadows={{
|
|
179
|
+
* fillStyle: { kind: 'color', color: 'rgba(0,0,0,0.15)' },
|
|
180
|
+
* blurRadius: blur,
|
|
181
|
+
* offsetY,
|
|
182
|
+
* spread,
|
|
183
|
+
* }}
|
|
184
|
+
* shape={{ kind: 'roundedRect', radius: 16 }}
|
|
185
|
+
* >
|
|
186
|
+
* <Pressable onPressIn={onPressIn} onPressOut={onPressOut}>
|
|
187
|
+
* <View style={styles.card}>
|
|
188
|
+
* <Text>Press me</Text>
|
|
189
|
+
* </View>
|
|
190
|
+
* </Pressable>
|
|
191
|
+
* </AnimatedShadow>
|
|
192
|
+
* );
|
|
193
|
+
* };
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
const AnimatedShadow = ({
|
|
197
|
+
shadows,
|
|
198
|
+
shape = {
|
|
199
|
+
kind: 'rect'
|
|
200
|
+
},
|
|
201
|
+
width: _width,
|
|
202
|
+
height: _height,
|
|
203
|
+
maxCanvasPadding = 120,
|
|
204
|
+
style,
|
|
205
|
+
children
|
|
206
|
+
}) => {
|
|
207
|
+
const [layout, setLayout] = useState(null);
|
|
208
|
+
const onLayout = e => {
|
|
209
|
+
const {
|
|
210
|
+
width,
|
|
211
|
+
height
|
|
212
|
+
} = e.nativeEvent.layout;
|
|
213
|
+
setLayout({
|
|
214
|
+
width,
|
|
215
|
+
height
|
|
216
|
+
});
|
|
217
|
+
};
|
|
218
|
+
const width = _width ?? layout?.width ?? 0;
|
|
219
|
+
const height = _height ?? layout?.height ?? 0;
|
|
220
|
+
const shadowList = Array.isArray(shadows) ? shadows : [shadows];
|
|
221
|
+
const hasSize = width > 0 && height > 0;
|
|
222
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
223
|
+
style: [styles.container, style],
|
|
224
|
+
onLayout: onLayout,
|
|
225
|
+
children: [hasSize && /*#__PURE__*/_jsx(Canvas, {
|
|
226
|
+
style: [styles.canvas, {
|
|
227
|
+
top: -maxCanvasPadding,
|
|
228
|
+
left: -maxCanvasPadding,
|
|
229
|
+
width: width + maxCanvasPadding * 2,
|
|
230
|
+
height: height + maxCanvasPadding * 2
|
|
231
|
+
}],
|
|
232
|
+
children: /*#__PURE__*/_jsx(Group, {
|
|
233
|
+
transform: [{
|
|
234
|
+
translateX: maxCanvasPadding
|
|
235
|
+
}, {
|
|
236
|
+
translateY: maxCanvasPadding
|
|
237
|
+
}],
|
|
238
|
+
children: shadowList.map((params, idx) => /*#__PURE__*/_jsx(AnimatedShadowLayer, {
|
|
239
|
+
params: params,
|
|
240
|
+
width: width,
|
|
241
|
+
height: height,
|
|
242
|
+
defaultShape: shape
|
|
243
|
+
}, idx))
|
|
244
|
+
})
|
|
245
|
+
}), children]
|
|
246
|
+
});
|
|
247
|
+
};
|
|
248
|
+
const styles = StyleSheet.create({
|
|
249
|
+
container: {},
|
|
250
|
+
canvas: {
|
|
251
|
+
position: 'absolute',
|
|
252
|
+
pointerEvents: 'none'
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
export default AnimatedShadow;
|
|
256
|
+
export { AnimatedShadow };
|
|
257
|
+
//# sourceMappingURL=AnimatedShadow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","useMemo","useState","StyleSheet","View","PixelRatio","Canvas","Group","RoundedRect","Rect","Circle","Path","Blur","Skia","useDerivedValue","jsx","_jsx","jsxs","_jsxs","DEFAULTS","fillStyle","kind","color","blurRadius","spread","offsetX","offsetY","pixelRatio","get","readValue","v","fallback","undefined","value","AnimatedShadowLayer","params","width","height","defaultShape","shape","shapeOverride","paint","p","Paint","setColor","Color","setShader","factory","derivedBlur","offsetTransform","translateX","translateY","scaleTransform","s","sw","sh","scaleX","scaleY","shapeElement","blurChild","blur","x","y","r","radius","children","Math","min","cx","cy","path","svgPath","transform","origin","AnimatedShadow","shadows","_width","_height","maxCanvasPadding","style","layout","setLayout","onLayout","e","nativeEvent","shadowList","Array","isArray","hasSize","styles","container","canvas","top","left","map","idx","create","position","pointerEvents"],"sourceRoot":"../../src","sources":["AnimatedShadow.tsx"],"mappings":"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","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["default","Shadow","ShadowView","ShadowDefaults"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,OAAO,IAAIC,MAAM,EAAEA,MAAM,IAAIC,UAAU,EAAEC,cAAc,QAAQ,UAAU","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["default","Shadow","ShadowView","ShadowDefaults","AnimatedShadow"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,OAAO,IAAIC,MAAM,EAAEA,MAAM,IAAIC,UAAU,EAAEC,cAAc,QAAQ,UAAU;AAClF,SAASC,cAAc,QAAQ,kBAAkB","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["types.animated.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AnimatedShadowProps } from './types.animated';
|
|
3
|
+
/**
|
|
4
|
+
* `<AnimatedShadow>` — Animated CSS-style box shadows.
|
|
5
|
+
*
|
|
6
|
+
* Same API as `<Shadow>`, but numeric props accept Reanimated
|
|
7
|
+
* `SharedValue<number>` for 60fps animations on the UI thread.
|
|
8
|
+
*
|
|
9
|
+
* Requires `react-native-reanimated` >= 3.0.0.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* import { AnimatedShadow } from 'react-native-skia-box-shadow';
|
|
14
|
+
* import { useSharedValue, withSpring } from 'react-native-reanimated';
|
|
15
|
+
*
|
|
16
|
+
* const MyCard = () => {
|
|
17
|
+
* const blur = useSharedValue(16);
|
|
18
|
+
* const offsetY = useSharedValue(4);
|
|
19
|
+
* const spread = useSharedValue(0);
|
|
20
|
+
*
|
|
21
|
+
* const onPressIn = () => {
|
|
22
|
+
* blur.value = withSpring(32);
|
|
23
|
+
* offsetY.value = withSpring(12);
|
|
24
|
+
* spread.value = withSpring(4);
|
|
25
|
+
* };
|
|
26
|
+
*
|
|
27
|
+
* const onPressOut = () => {
|
|
28
|
+
* blur.value = withSpring(16);
|
|
29
|
+
* offsetY.value = withSpring(4);
|
|
30
|
+
* spread.value = withSpring(0);
|
|
31
|
+
* };
|
|
32
|
+
*
|
|
33
|
+
* return (
|
|
34
|
+
* <AnimatedShadow
|
|
35
|
+
* shadows={{
|
|
36
|
+
* fillStyle: { kind: 'color', color: 'rgba(0,0,0,0.15)' },
|
|
37
|
+
* blurRadius: blur,
|
|
38
|
+
* offsetY,
|
|
39
|
+
* spread,
|
|
40
|
+
* }}
|
|
41
|
+
* shape={{ kind: 'roundedRect', radius: 16 }}
|
|
42
|
+
* >
|
|
43
|
+
* <Pressable onPressIn={onPressIn} onPressOut={onPressOut}>
|
|
44
|
+
* <View style={styles.card}>
|
|
45
|
+
* <Text>Press me</Text>
|
|
46
|
+
* </View>
|
|
47
|
+
* </Pressable>
|
|
48
|
+
* </AnimatedShadow>
|
|
49
|
+
* );
|
|
50
|
+
* };
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
declare const AnimatedShadow: React.FC<AnimatedShadowProps>;
|
|
54
|
+
export default AnimatedShadow;
|
|
55
|
+
export { AnimatedShadow };
|
|
56
|
+
//# sourceMappingURL=AnimatedShadow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnimatedShadow.d.ts","sourceRoot":"","sources":["../../src/AnimatedShadow.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAmBjD,OAAO,KAAK,EAGV,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;AAuI1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,QAAA,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA8DjD,CAAC;AAUF,eAAe,cAAc,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { default as Shadow, Shadow as ShadowView, ShadowDefaults } from './Shadow';
|
|
2
|
+
export { AnimatedShadow } from './AnimatedShadow';
|
|
2
3
|
export type { ShadowProps, ShadowParams, ShadowShape, ShadowFillStyle, } from './types';
|
|
4
|
+
export type { AnimatedShadowProps, AnimatedShadowParams, Animatable, } from './types.animated';
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,IAAI,UAAU,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACnF,YAAY,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACX,eAAe,GAChB,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,IAAI,UAAU,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACX,eAAe,GAChB,MAAM,SAAS,CAAC;AACjB,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,UAAU,GACX,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { SharedValue } from 'react-native-reanimated';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import type { ViewStyle, StyleProp } from 'react-native';
|
|
4
|
+
import type { ShadowShape, ShadowFillStyle } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* A value that can be either static or a Reanimated SharedValue.
|
|
7
|
+
* When animated, Skia reads it directly on the UI thread — no React re-renders.
|
|
8
|
+
*/
|
|
9
|
+
export type Animatable<T> = T | SharedValue<T>;
|
|
10
|
+
/**
|
|
11
|
+
* Animated shadow layer descriptor.
|
|
12
|
+
* Any numeric prop can be a SharedValue for 60fps animation.
|
|
13
|
+
*/
|
|
14
|
+
export interface AnimatedShadowParams {
|
|
15
|
+
/** Fill style (not animatable — use opacity in color for fade effects) */
|
|
16
|
+
fillStyle?: ShadowFillStyle;
|
|
17
|
+
/** Gaussian blur radius. Animatable. Default: 24 */
|
|
18
|
+
blurRadius?: Animatable<number>;
|
|
19
|
+
/** Expands the shadow outline beyond element bounds. Animatable. Default: 4 */
|
|
20
|
+
spread?: Animatable<number>;
|
|
21
|
+
/** Horizontal offset. Animatable. Default: 0 */
|
|
22
|
+
offsetX?: Animatable<number>;
|
|
23
|
+
/** Vertical offset. Animatable. Default: 0 */
|
|
24
|
+
offsetY?: Animatable<number>;
|
|
25
|
+
/** Shape override for this layer */
|
|
26
|
+
shape?: ShadowShape;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Props for the `<AnimatedShadow>` component.
|
|
30
|
+
*/
|
|
31
|
+
export interface AnimatedShadowProps {
|
|
32
|
+
/** One or more animated shadow layers */
|
|
33
|
+
shadows: AnimatedShadowParams | AnimatedShadowParams[];
|
|
34
|
+
/** Default shape. Default: rect */
|
|
35
|
+
shape?: ShadowShape;
|
|
36
|
+
/** Explicit width */
|
|
37
|
+
width?: number;
|
|
38
|
+
/** Explicit height */
|
|
39
|
+
height?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Maximum canvas padding to accommodate animated values.
|
|
42
|
+
* Since blur/spread/offset may change at runtime, set this to
|
|
43
|
+
* the largest extent the shadow can reach.
|
|
44
|
+
* Default: 120
|
|
45
|
+
*/
|
|
46
|
+
maxCanvasPadding?: number;
|
|
47
|
+
/** RN style for the outer container */
|
|
48
|
+
style?: StyleProp<ViewStyle>;
|
|
49
|
+
/** Content rendered above the shadow */
|
|
50
|
+
children?: ReactNode;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=types.animated.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.animated.d.ts","sourceRoot":"","sources":["../../src/types.animated.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE5D;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;AAE/C;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,0EAA0E;IAC1E,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,oDAAoD;IACpD,UAAU,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAChC,+EAA+E;IAC/E,MAAM,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC5B,gDAAgD;IAChD,OAAO,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC7B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC7B,oCAAoC;IACpC,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,yCAAyC;IACzC,OAAO,EAAE,oBAAoB,GAAG,oBAAoB,EAAE,CAAC;IACvD,mCAAmC;IACnC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uCAAuC;IACvC,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-skia-box-shadow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CSS-style box shadows for React Native — blur, spread, offset, colors, gradients, and arbitrary shapes. Powered by @shopify/react-native-skia.",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -30,11 +30,13 @@
|
|
|
30
30
|
"spread",
|
|
31
31
|
"ios",
|
|
32
32
|
"android",
|
|
33
|
-
"react-native-skia"
|
|
33
|
+
"react-native-skia",
|
|
34
|
+
"animated",
|
|
35
|
+
"reanimated"
|
|
34
36
|
],
|
|
35
37
|
"repository": {
|
|
36
38
|
"type": "git",
|
|
37
|
-
"url": "git+https://github.com/
|
|
39
|
+
"url": "git+https://github.com/vasyl-stetsiuk/react-native-skia-box-shadow.git"
|
|
38
40
|
},
|
|
39
41
|
"author": {
|
|
40
42
|
"name": "Vasyl Stetsiuk",
|
|
@@ -42,26 +44,31 @@
|
|
|
42
44
|
},
|
|
43
45
|
"license": "MIT",
|
|
44
46
|
"bugs": {
|
|
45
|
-
"url": "https://github.com/
|
|
47
|
+
"url": "https://github.com/vasyl-stetsiuk/react-native-skia-box-shadow/issues"
|
|
46
48
|
},
|
|
47
|
-
"homepage": "https://github.com/
|
|
49
|
+
"homepage": "https://github.com/vasyl-stetsiuk/react-native-skia-box-shadow#readme",
|
|
48
50
|
"peerDependencies": {
|
|
49
51
|
"@shopify/react-native-skia": ">=1.0.0",
|
|
50
52
|
"react": ">=18.0.0",
|
|
51
|
-
"react-native": ">=0.71.0"
|
|
53
|
+
"react-native": ">=0.71.0",
|
|
54
|
+
"react-native-reanimated": ">=3.0.0"
|
|
52
55
|
},
|
|
53
56
|
"peerDependenciesMeta": {
|
|
54
57
|
"@shopify/react-native-skia": {
|
|
55
58
|
"optional": false
|
|
59
|
+
},
|
|
60
|
+
"react-native-reanimated": {
|
|
61
|
+
"optional": true
|
|
56
62
|
}
|
|
57
63
|
},
|
|
58
64
|
"devDependencies": {
|
|
59
65
|
"@shopify/react-native-skia": "^1.11.0",
|
|
60
66
|
"@types/react": "^18.2.0",
|
|
61
|
-
"@types/react-native": "^0.
|
|
67
|
+
"@types/react-native": "^0.73.0",
|
|
62
68
|
"react": "^18.2.0",
|
|
63
69
|
"react-native": "^0.75.0",
|
|
64
70
|
"react-native-builder-bob": "^0.30.0",
|
|
71
|
+
"react-native-reanimated": "^3.16.0",
|
|
65
72
|
"typescript": "^5.4.0"
|
|
66
73
|
},
|
|
67
74
|
"react-native-builder-bob": {
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
StyleSheet,
|
|
4
|
+
View,
|
|
5
|
+
PixelRatio,
|
|
6
|
+
type LayoutChangeEvent,
|
|
7
|
+
} from 'react-native';
|
|
8
|
+
import {
|
|
9
|
+
Canvas,
|
|
10
|
+
Group,
|
|
11
|
+
RoundedRect,
|
|
12
|
+
Rect,
|
|
13
|
+
Circle,
|
|
14
|
+
Path,
|
|
15
|
+
Blur,
|
|
16
|
+
Skia,
|
|
17
|
+
} from '@shopify/react-native-skia';
|
|
18
|
+
|
|
19
|
+
import type { ShadowShape, ShadowFillStyle } from './types';
|
|
20
|
+
import type {
|
|
21
|
+
Animatable,
|
|
22
|
+
AnimatedShadowParams,
|
|
23
|
+
AnimatedShadowProps,
|
|
24
|
+
} from './types.animated';
|
|
25
|
+
import {useDerivedValue} from "react-native-reanimated";
|
|
26
|
+
|
|
27
|
+
// ── Defaults ────────────────────────────────────────────────────
|
|
28
|
+
const DEFAULTS = {
|
|
29
|
+
fillStyle: { kind: 'color', color: 'rgba(0,0,0,0.10)' } as ShadowFillStyle,
|
|
30
|
+
blurRadius: 24,
|
|
31
|
+
spread: 4,
|
|
32
|
+
offsetX: 0,
|
|
33
|
+
offsetY: 0,
|
|
34
|
+
} as const;
|
|
35
|
+
|
|
36
|
+
const pixelRatio = PixelRatio.get();
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Read a value that may be static or a SharedValue.
|
|
40
|
+
* Called inside useDerivedValue / on UI thread.
|
|
41
|
+
*/
|
|
42
|
+
const readValue = (v: Animatable<number>, fallback: number): number => {
|
|
43
|
+
'worklet';
|
|
44
|
+
if (typeof v === 'number') return v;
|
|
45
|
+
if (v === undefined || v === null) return fallback;
|
|
46
|
+
return v.value;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// ── Animated single shadow layer ────────────────────────────────
|
|
50
|
+
const AnimatedShadowLayer: React.FC<{
|
|
51
|
+
params: AnimatedShadowParams;
|
|
52
|
+
width: number;
|
|
53
|
+
height: number;
|
|
54
|
+
defaultShape: ShadowShape;
|
|
55
|
+
}> = ({ params, width, height, defaultShape }) => {
|
|
56
|
+
const {
|
|
57
|
+
fillStyle = DEFAULTS.fillStyle,
|
|
58
|
+
blurRadius = DEFAULTS.blurRadius,
|
|
59
|
+
spread = DEFAULTS.spread,
|
|
60
|
+
offsetX = DEFAULTS.offsetX,
|
|
61
|
+
offsetY = DEFAULTS.offsetY,
|
|
62
|
+
shape: shapeOverride,
|
|
63
|
+
} = params;
|
|
64
|
+
|
|
65
|
+
const shape = shapeOverride ?? defaultShape;
|
|
66
|
+
|
|
67
|
+
// ── Paint (static — color changes don't need 60fps) ───────────
|
|
68
|
+
const paint = useMemo(() => {
|
|
69
|
+
const p = Skia.Paint();
|
|
70
|
+
if (fillStyle.kind === 'color') {
|
|
71
|
+
p.setColor(Skia.Color(fillStyle.color));
|
|
72
|
+
} else {
|
|
73
|
+
p.setShader(fillStyle.factory(width, height));
|
|
74
|
+
}
|
|
75
|
+
return p;
|
|
76
|
+
}, [fillStyle, width, height]);
|
|
77
|
+
|
|
78
|
+
// ── Animated blur (derived on UI thread) ──────────────────────
|
|
79
|
+
const derivedBlur = useDerivedValue(() => {
|
|
80
|
+
return readValue(blurRadius, DEFAULTS.blurRadius) / pixelRatio;
|
|
81
|
+
}, [blurRadius]);
|
|
82
|
+
|
|
83
|
+
// ── Animated offset transform ─────────────────────────────────
|
|
84
|
+
const offsetTransform = useDerivedValue(() => {
|
|
85
|
+
return [
|
|
86
|
+
{ translateX: readValue(offsetX, DEFAULTS.offsetX) },
|
|
87
|
+
{ translateY: readValue(offsetY, DEFAULTS.offsetY) },
|
|
88
|
+
];
|
|
89
|
+
}, [offsetX, offsetY]);
|
|
90
|
+
|
|
91
|
+
// ── Animated spread transform ─────────────────────────────────
|
|
92
|
+
const scaleTransform = useDerivedValue(() => {
|
|
93
|
+
const s = readValue(spread, DEFAULTS.spread);
|
|
94
|
+
const sw = width + s * 2;
|
|
95
|
+
const sh = height + s * 2;
|
|
96
|
+
return [
|
|
97
|
+
{ scaleX: width > 0 ? sw / width : 1 },
|
|
98
|
+
{ scaleY: height > 0 ? sh / height : 1 },
|
|
99
|
+
];
|
|
100
|
+
}, [spread, width, height]);
|
|
101
|
+
|
|
102
|
+
// ── Shape element ─────────────────────────────────────────────
|
|
103
|
+
const shapeElement = useMemo(() => {
|
|
104
|
+
const blurChild = <Blur blur={derivedBlur} />;
|
|
105
|
+
|
|
106
|
+
switch (shape.kind) {
|
|
107
|
+
case 'roundedRect':
|
|
108
|
+
return (
|
|
109
|
+
<RoundedRect
|
|
110
|
+
x={0}
|
|
111
|
+
y={0}
|
|
112
|
+
width={width}
|
|
113
|
+
height={height}
|
|
114
|
+
r={shape.radius}
|
|
115
|
+
paint={paint}
|
|
116
|
+
>
|
|
117
|
+
{blurChild}
|
|
118
|
+
</RoundedRect>
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
case 'circle': {
|
|
122
|
+
const r = Math.min(width, height) / 2;
|
|
123
|
+
return (
|
|
124
|
+
<Circle cx={width / 2} cy={height / 2} r={r} paint={paint}>
|
|
125
|
+
{blurChild}
|
|
126
|
+
</Circle>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
case 'path':
|
|
131
|
+
return (
|
|
132
|
+
<Path path={shape.svgPath} paint={paint}>
|
|
133
|
+
{blurChild}
|
|
134
|
+
</Path>
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
case 'rect':
|
|
138
|
+
default:
|
|
139
|
+
return (
|
|
140
|
+
<Rect x={0} y={0} width={width} height={height} paint={paint}>
|
|
141
|
+
{blurChild}
|
|
142
|
+
</Rect>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}, [shape, width, height, paint, derivedBlur]);
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<Group transform={offsetTransform}>
|
|
149
|
+
<Group
|
|
150
|
+
transform={scaleTransform}
|
|
151
|
+
origin={{ x: width / 2, y: height / 2 }}
|
|
152
|
+
>
|
|
153
|
+
{shapeElement}
|
|
154
|
+
</Group>
|
|
155
|
+
</Group>
|
|
156
|
+
);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* `<AnimatedShadow>` — Animated CSS-style box shadows.
|
|
161
|
+
*
|
|
162
|
+
* Same API as `<Shadow>`, but numeric props accept Reanimated
|
|
163
|
+
* `SharedValue<number>` for 60fps animations on the UI thread.
|
|
164
|
+
*
|
|
165
|
+
* Requires `react-native-reanimated` >= 3.0.0.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```tsx
|
|
169
|
+
* import { AnimatedShadow } from 'react-native-skia-box-shadow';
|
|
170
|
+
* import { useSharedValue, withSpring } from 'react-native-reanimated';
|
|
171
|
+
*
|
|
172
|
+
* const MyCard = () => {
|
|
173
|
+
* const blur = useSharedValue(16);
|
|
174
|
+
* const offsetY = useSharedValue(4);
|
|
175
|
+
* const spread = useSharedValue(0);
|
|
176
|
+
*
|
|
177
|
+
* const onPressIn = () => {
|
|
178
|
+
* blur.value = withSpring(32);
|
|
179
|
+
* offsetY.value = withSpring(12);
|
|
180
|
+
* spread.value = withSpring(4);
|
|
181
|
+
* };
|
|
182
|
+
*
|
|
183
|
+
* const onPressOut = () => {
|
|
184
|
+
* blur.value = withSpring(16);
|
|
185
|
+
* offsetY.value = withSpring(4);
|
|
186
|
+
* spread.value = withSpring(0);
|
|
187
|
+
* };
|
|
188
|
+
*
|
|
189
|
+
* return (
|
|
190
|
+
* <AnimatedShadow
|
|
191
|
+
* shadows={{
|
|
192
|
+
* fillStyle: { kind: 'color', color: 'rgba(0,0,0,0.15)' },
|
|
193
|
+
* blurRadius: blur,
|
|
194
|
+
* offsetY,
|
|
195
|
+
* spread,
|
|
196
|
+
* }}
|
|
197
|
+
* shape={{ kind: 'roundedRect', radius: 16 }}
|
|
198
|
+
* >
|
|
199
|
+
* <Pressable onPressIn={onPressIn} onPressOut={onPressOut}>
|
|
200
|
+
* <View style={styles.card}>
|
|
201
|
+
* <Text>Press me</Text>
|
|
202
|
+
* </View>
|
|
203
|
+
* </Pressable>
|
|
204
|
+
* </AnimatedShadow>
|
|
205
|
+
* );
|
|
206
|
+
* };
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
const AnimatedShadow: React.FC<AnimatedShadowProps> = ({
|
|
210
|
+
shadows,
|
|
211
|
+
shape = { kind: 'rect' },
|
|
212
|
+
width: _width,
|
|
213
|
+
height: _height,
|
|
214
|
+
maxCanvasPadding = 120,
|
|
215
|
+
style,
|
|
216
|
+
children,
|
|
217
|
+
}) => {
|
|
218
|
+
const [layout, setLayout] = useState<{
|
|
219
|
+
width: number;
|
|
220
|
+
height: number;
|
|
221
|
+
} | null>(null);
|
|
222
|
+
|
|
223
|
+
const onLayout = (e: LayoutChangeEvent) => {
|
|
224
|
+
const { width, height } = e.nativeEvent.layout;
|
|
225
|
+
setLayout({ width, height });
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const width = _width ?? layout?.width ?? 0;
|
|
229
|
+
const height = _height ?? layout?.height ?? 0;
|
|
230
|
+
|
|
231
|
+
const shadowList = Array.isArray(shadows) ? shadows : [shadows];
|
|
232
|
+
|
|
233
|
+
const hasSize = width > 0 && height > 0;
|
|
234
|
+
|
|
235
|
+
return (
|
|
236
|
+
<View style={[styles.container, style]} onLayout={onLayout}>
|
|
237
|
+
{hasSize && (
|
|
238
|
+
<Canvas
|
|
239
|
+
style={[
|
|
240
|
+
styles.canvas,
|
|
241
|
+
{
|
|
242
|
+
top: -maxCanvasPadding,
|
|
243
|
+
left: -maxCanvasPadding,
|
|
244
|
+
width: width + maxCanvasPadding * 2,
|
|
245
|
+
height: height + maxCanvasPadding * 2,
|
|
246
|
+
},
|
|
247
|
+
]}
|
|
248
|
+
>
|
|
249
|
+
<Group
|
|
250
|
+
transform={[
|
|
251
|
+
{ translateX: maxCanvasPadding },
|
|
252
|
+
{ translateY: maxCanvasPadding },
|
|
253
|
+
]}
|
|
254
|
+
>
|
|
255
|
+
{shadowList.map((params, idx) => (
|
|
256
|
+
<AnimatedShadowLayer
|
|
257
|
+
key={idx}
|
|
258
|
+
params={params}
|
|
259
|
+
width={width}
|
|
260
|
+
height={height}
|
|
261
|
+
defaultShape={shape}
|
|
262
|
+
/>
|
|
263
|
+
))}
|
|
264
|
+
</Group>
|
|
265
|
+
</Canvas>
|
|
266
|
+
)}
|
|
267
|
+
|
|
268
|
+
{children}
|
|
269
|
+
</View>
|
|
270
|
+
);
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const styles = StyleSheet.create({
|
|
274
|
+
container: {},
|
|
275
|
+
canvas: {
|
|
276
|
+
position: 'absolute',
|
|
277
|
+
pointerEvents: 'none',
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
export default AnimatedShadow;
|
|
282
|
+
export { AnimatedShadow };
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
export { default as Shadow, Shadow as ShadowView, ShadowDefaults } from './Shadow';
|
|
2
|
+
export { AnimatedShadow } from './AnimatedShadow';
|
|
2
3
|
export type {
|
|
3
4
|
ShadowProps,
|
|
4
5
|
ShadowParams,
|
|
5
6
|
ShadowShape,
|
|
6
7
|
ShadowFillStyle,
|
|
7
8
|
} from './types';
|
|
9
|
+
export type {
|
|
10
|
+
AnimatedShadowProps,
|
|
11
|
+
AnimatedShadowParams,
|
|
12
|
+
Animatable,
|
|
13
|
+
} from './types.animated';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { SharedValue } from 'react-native-reanimated';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import type { ViewStyle, StyleProp } from 'react-native';
|
|
4
|
+
import type { ShadowShape, ShadowFillStyle } from './types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A value that can be either static or a Reanimated SharedValue.
|
|
8
|
+
* When animated, Skia reads it directly on the UI thread — no React re-renders.
|
|
9
|
+
*/
|
|
10
|
+
export type Animatable<T> = T | SharedValue<T>;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Animated shadow layer descriptor.
|
|
14
|
+
* Any numeric prop can be a SharedValue for 60fps animation.
|
|
15
|
+
*/
|
|
16
|
+
export interface AnimatedShadowParams {
|
|
17
|
+
/** Fill style (not animatable — use opacity in color for fade effects) */
|
|
18
|
+
fillStyle?: ShadowFillStyle;
|
|
19
|
+
/** Gaussian blur radius. Animatable. Default: 24 */
|
|
20
|
+
blurRadius?: Animatable<number>;
|
|
21
|
+
/** Expands the shadow outline beyond element bounds. Animatable. Default: 4 */
|
|
22
|
+
spread?: Animatable<number>;
|
|
23
|
+
/** Horizontal offset. Animatable. Default: 0 */
|
|
24
|
+
offsetX?: Animatable<number>;
|
|
25
|
+
/** Vertical offset. Animatable. Default: 0 */
|
|
26
|
+
offsetY?: Animatable<number>;
|
|
27
|
+
/** Shape override for this layer */
|
|
28
|
+
shape?: ShadowShape;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Props for the `<AnimatedShadow>` component.
|
|
33
|
+
*/
|
|
34
|
+
export interface AnimatedShadowProps {
|
|
35
|
+
/** One or more animated shadow layers */
|
|
36
|
+
shadows: AnimatedShadowParams | AnimatedShadowParams[];
|
|
37
|
+
/** Default shape. Default: rect */
|
|
38
|
+
shape?: ShadowShape;
|
|
39
|
+
/** Explicit width */
|
|
40
|
+
width?: number;
|
|
41
|
+
/** Explicit height */
|
|
42
|
+
height?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Maximum canvas padding to accommodate animated values.
|
|
45
|
+
* Since blur/spread/offset may change at runtime, set this to
|
|
46
|
+
* the largest extent the shadow can reach.
|
|
47
|
+
* Default: 120
|
|
48
|
+
*/
|
|
49
|
+
maxCanvasPadding?: number;
|
|
50
|
+
/** RN style for the outer container */
|
|
51
|
+
style?: StyleProp<ViewStyle>;
|
|
52
|
+
/** Content rendered above the shadow */
|
|
53
|
+
children?: ReactNode;
|
|
54
|
+
}
|