react-native-smooth-clip-view 0.5.0 → 0.5.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/CHANGELOG.md +14 -0
- package/ios/SmoothClipView.mm +38 -28
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.1](https://github.com/kbrattli/react-native-smooth-clip-view/releases/tag/v0.5.1) — 2026-09-28
|
|
4
|
+
|
|
5
|
+
- **Fix: iOS baked shadows were invisible.** `shadowRendering="baked"` baked
|
|
6
|
+
its tile by rendering a shadowPath-only layer through `renderInContext:`,
|
|
7
|
+
which draws a layer's shadow only where the layer has content of its own,
|
|
8
|
+
so every tile was fully transparent and a baked host drew no shadow at all.
|
|
9
|
+
The tile is now drawn as a Core Graphics shadow inside a UIKit image
|
|
10
|
+
renderer, whose base transform also scales the blur with the tile's scale
|
|
11
|
+
(a hand-scaled bitmap context left the shadow in pixel space). A Core
|
|
12
|
+
Graphics shadow of `blur` has the same sigma as Core Animation's
|
|
13
|
+
`shadowRadius = blur / 2`, so the tile matches the blur path's shadow
|
|
14
|
+
sample for sample; the iOS and Android suites now pin the tile's alpha
|
|
15
|
+
profile. Android tiles were unaffected.
|
|
16
|
+
|
|
3
17
|
## [0.5.0](https://github.com/kbrattli/react-native-smooth-clip-view/releases/tag/v0.5.0) — 2026-09-28
|
|
4
18
|
|
|
5
19
|
- **Backdrop channel.** A presentation gains `backdrop: { translateX,
|
package/ios/SmoothClipView.mm
CHANGED
|
@@ -445,9 +445,16 @@ static CGFloat SmoothClipBakedShadowMargin(const smoothclip::Shadow &shadow) {
|
|
|
445
445
|
}
|
|
446
446
|
|
|
447
447
|
// Baked once per (radius step, curve, blur, colour, scale) and cached for the
|
|
448
|
-
// process.
|
|
449
|
-
//
|
|
450
|
-
//
|
|
448
|
+
// process. The tile is the pure blurred shape the compositor draws for a
|
|
449
|
+
// `shadowPath` layer, with nothing filled in on top of it; colour alpha is
|
|
450
|
+
// applied as layer opacity. It is drawn with a Core Graphics shadow, not by
|
|
451
|
+
// rendering a layer: `renderInContext:` draws a layer's shadow only where the
|
|
452
|
+
// layer has content of its own, so a shadowPath-only layer renders nothing.
|
|
453
|
+
// A Core Graphics shadow of `b` has sigma b / 2, the same sigma Core
|
|
454
|
+
// Animation gives `shadowRadius` b / 2 (the blur path's setting), so the two
|
|
455
|
+
// tails match sample for sample. The context comes from a UIKit image
|
|
456
|
+
// renderer, whose base transform scales the blur with the tile's scale; a
|
|
457
|
+
// hand-scaled CGBitmapContext leaves the shadow in pixel space.
|
|
451
458
|
static NSCache<NSString *, SmoothClipShadowTile *> *SmoothClipShadowTileCache(void) {
|
|
452
459
|
static NSCache<NSString *, SmoothClipShadowTile *> *cache;
|
|
453
460
|
static dispatch_once_t once;
|
|
@@ -523,41 +530,44 @@ static SmoothClipShadowTile *SmoothClipBakeShadowTile(
|
|
|
523
530
|
const CGFloat margin = SmoothClipBakedShadowMargin(shadow);
|
|
524
531
|
|
|
525
532
|
const CGFloat side = 2 * (2 * margin + tileRadius) + kSmoothClipShadowTileBand;
|
|
526
|
-
const
|
|
527
|
-
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
|
|
528
|
-
CGContextRef context = CGBitmapContextCreate(
|
|
529
|
-
NULL, pixels, pixels, 8, 0, space,
|
|
530
|
-
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
|
|
531
|
-
CGColorSpaceRelease(space);
|
|
532
|
-
if (context == NULL) return nil;
|
|
533
|
-
CGContextScaleCTM(context, scale, scale);
|
|
534
|
-
CALayer *layer = [CALayer layer];
|
|
535
|
-
layer.frame = CGRectMake(0, 0, side, side);
|
|
536
|
-
const CGRect shape = CGRectInset(layer.bounds, margin, margin);
|
|
533
|
+
const CGRect shape = CGRectInset(CGRectMake(0, 0, side, side), margin, margin);
|
|
537
534
|
const SmoothClipCornerRadii radii = {
|
|
538
535
|
tileRadius, tileRadius, tileRadius, tileRadius};
|
|
539
536
|
CGPathRef path = SmoothClipCreateRoundedRectPath(shape, radii, curve);
|
|
540
|
-
|
|
537
|
+
CGColorRef color = [UIColor colorWithRed:smoothclip::clamp01(shadow.red)
|
|
538
|
+
green:smoothclip::clamp01(shadow.green)
|
|
539
|
+
blue:smoothclip::clamp01(shadow.blue)
|
|
540
|
+
alpha:1].CGColor;
|
|
541
|
+
const CGFloat blur = MAX(0, shadow.blurRadius);
|
|
542
|
+
UIGraphicsImageRendererFormat *format =
|
|
543
|
+
[UIGraphicsImageRendererFormat defaultFormat];
|
|
544
|
+
format.scale = scale;
|
|
545
|
+
format.opaque = NO;
|
|
546
|
+
format.preferredRange = UIGraphicsImageRendererFormatRangeStandard;
|
|
547
|
+
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc]
|
|
548
|
+
initWithSize:CGSizeMake(side, side) format:format];
|
|
549
|
+
UIImage *rendered = [renderer imageWithActions:^(
|
|
550
|
+
UIGraphicsImageRendererContext *rendererContext) {
|
|
551
|
+
CGContextRef context = rendererContext.CGContext;
|
|
552
|
+
// Only the shadow lands on the tile: the shape itself is filled far
|
|
553
|
+
// outside the bitmap and its shadow offset back by the same distance,
|
|
554
|
+
// so the interior keeps the blurred shape's own profile (0.5 at the
|
|
555
|
+
// edge) instead of a hard fill.
|
|
556
|
+
const CGFloat away = 4 * side;
|
|
557
|
+
CGContextSetShadowWithColor(context, CGSizeMake(0, -away), blur, color);
|
|
558
|
+
CGContextTranslateCTM(context, 0, away);
|
|
559
|
+
CGContextAddPath(context, path);
|
|
560
|
+
CGContextSetFillColorWithColor(context, color);
|
|
561
|
+
CGContextFillPath(context);
|
|
562
|
+
}];
|
|
541
563
|
CGPathRelease(path);
|
|
542
|
-
|
|
543
|
-
green:smoothclip::clamp01(shadow.green)
|
|
544
|
-
blue:smoothclip::clamp01(shadow.blue)
|
|
545
|
-
alpha:1].CGColor;
|
|
546
|
-
layer.shadowOpacity = 1;
|
|
547
|
-
layer.shadowOffset = CGSizeZero;
|
|
548
|
-
layer.shadowRadius = MAX(0, shadow.blurRadius) / 2.0;
|
|
549
|
-
// The bitmap's y axis is flipped relative to the layer; the tile is
|
|
550
|
-
// symmetric (uniform radii, no offset), so that is harmless.
|
|
551
|
-
[layer renderInContext:context];
|
|
552
|
-
CGImageRef image = CGBitmapContextCreateImage(context);
|
|
553
|
-
CGContextRelease(context);
|
|
564
|
+
CGImageRef image = rendered.CGImage;
|
|
554
565
|
if (image == NULL) return nil;
|
|
555
566
|
tile = [[SmoothClipShadowTile alloc] initWithImage:image
|
|
556
567
|
radius:tileRadius
|
|
557
568
|
margin:margin
|
|
558
569
|
side:side
|
|
559
570
|
scale:scale];
|
|
560
|
-
CGImageRelease(image);
|
|
561
571
|
[SmoothClipShadowTileCache() setObject:tile forKey:key];
|
|
562
572
|
return tile;
|
|
563
573
|
}
|
package/package.json
CHANGED