mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-06 07:06:11 +00:00
feat: get currentColor from caller instead of parent (#2521)
# Summary Fixes #2520 When an element uses `currentColor`, it should look for color in its caller, not in its parent. Example: ```svg <Svg width="100" height="100" viewBox="0 0 100 100" color="red"> <Defs color="blue"> <G color="green"> <Rect id="a" x="0" y="0" width="50" height="50" fill="currentColor"/> </G> </Defs> <G color="pink"> <Use href="#a"/> <!-- #1 --> </G> <Use href="#a" transform="translate(25 25)"/> <!-- #2 --> <G color="green"> <Use href="#a" transform="translate(50 50)"/> <!-- #3 --> </G> </Svg> ``` * `#1` should be **pink** * `#2` should be **red** * `#3` should be **green**  ## Test Plan Example app -> test -> Test2520 ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | MacOS | ✅ | | Android | ✅ |
This commit is contained in:
@@ -49,7 +49,7 @@
|
||||
BOOL fillColor;
|
||||
|
||||
if (brush.class == RNSVGBrush.class) {
|
||||
CGContextSetFillColorWithColor(context, [element.tintColor CGColor]);
|
||||
CGContextSetFillColorWithColor(context, [element getCurrentColor]);
|
||||
fillColor = YES;
|
||||
} else {
|
||||
fillColor = [brush applyFillColor:context opacity:opacity];
|
||||
@@ -70,7 +70,7 @@
|
||||
BOOL strokeColor;
|
||||
|
||||
if (brush.class == RNSVGBrush.class) {
|
||||
CGContextSetStrokeColorWithColor(context, [element.tintColor CGColor]);
|
||||
CGContextSetStrokeColorWithColor(context, [element getCurrentColor]);
|
||||
strokeColor = YES;
|
||||
} else {
|
||||
strokeColor = [brush applyStrokeColor:context opacity:opacity];
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
@interface RNSVGSvgView : RNSVGView <RNSVGContainer>
|
||||
|
||||
@property (nonatomic, strong) RNSVGColor *color;
|
||||
@property (nonatomic, strong) RNSVGLength *bbWidth;
|
||||
@property (nonatomic, strong) RNSVGLength *bbHeight;
|
||||
@property (nonatomic, assign) CGFloat minX;
|
||||
|
||||
@@ -47,8 +47,6 @@ using namespace facebook::react;
|
||||
// This is necessary to ensure that [self setNeedsDisplay] actually triggers
|
||||
// a redraw when our parent transitions between hidden and visible.
|
||||
self.contentMode = UIViewContentModeRedraw;
|
||||
// We don't want the dimming effect on tint as it's used as currentColor
|
||||
self.tintAdjustmentMode = UIViewTintAdjustmentModeNormal;
|
||||
#endif // TARGET_OS_OSX
|
||||
rendered = false;
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
@@ -90,7 +88,7 @@ using namespace facebook::react;
|
||||
self.align = RCTNSStringFromStringNilIfEmpty(newProps.align);
|
||||
self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice);
|
||||
if (RCTUIColorFromSharedColor(newProps.color)) {
|
||||
self.tintColor = RCTUIColorFromSharedColor(newProps.color);
|
||||
self.color = RCTUIColorFromSharedColor(newProps.color);
|
||||
}
|
||||
[super updateProps:props oldProps:oldProps];
|
||||
}
|
||||
@@ -184,10 +182,13 @@ using namespace facebook::react;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void)tintColorDidChange
|
||||
- (void)setColor:(RNSVGColor *)color
|
||||
{
|
||||
if (color == _color) {
|
||||
return;
|
||||
}
|
||||
[self invalidate];
|
||||
[self clearChildCache];
|
||||
_color = color;
|
||||
}
|
||||
|
||||
- (void)setMinX:(CGFloat)minX
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
@interface RNSVGRenderable : RNSVGNode
|
||||
|
||||
@property (class) RNSVGRenderable *contextElement;
|
||||
@property (nonatomic, strong) RNSVGColor *color;
|
||||
@property (nonatomic, strong) RNSVGBrush *fill;
|
||||
@property (nonatomic, assign) CGFloat fillOpacity;
|
||||
@property (nonatomic, assign) RNSVGCGFCRule fillRule;
|
||||
@@ -45,4 +46,6 @@
|
||||
|
||||
- (void)resetProperties;
|
||||
|
||||
- (CGColor *)getCurrentColor;
|
||||
|
||||
@end
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
NSArray<RNSVGLength *> *_sourceStrokeDashArray;
|
||||
CGFloat *_strokeDashArrayData;
|
||||
CGPathRef _srcHitPath;
|
||||
RNSVGRenderable *_caller;
|
||||
}
|
||||
|
||||
static RNSVGRenderable *_contextElement;
|
||||
@@ -61,11 +62,11 @@ static RNSVGRenderable *_contextElement;
|
||||
|
||||
- (void)setColor:(RNSVGColor *)color
|
||||
{
|
||||
if (color == self.tintColor) {
|
||||
if (color == _color) {
|
||||
return;
|
||||
}
|
||||
[self invalidate];
|
||||
self.tintColor = color;
|
||||
_color = color;
|
||||
}
|
||||
|
||||
- (void)setFill:(RNSVGBrush *)fill
|
||||
@@ -560,7 +561,7 @@ UInt32 saturate(CGFloat value)
|
||||
|
||||
if (self.fill) {
|
||||
if (self.fill.class == RNSVGBrush.class) {
|
||||
CGContextSetFillColorWithColor(context, [self.tintColor CGColor]);
|
||||
CGContextSetFillColorWithColor(context, [self getCurrentColor]);
|
||||
fillColor = YES;
|
||||
} else {
|
||||
fillColor = [self.fill applyFillColor:context opacity:self.fillOpacity];
|
||||
@@ -608,7 +609,7 @@ UInt32 saturate(CGFloat value)
|
||||
BOOL strokeColor;
|
||||
|
||||
if (self.stroke.class == RNSVGBrush.class) {
|
||||
CGContextSetStrokeColorWithColor(context, [self.tintColor CGColor]);
|
||||
CGContextSetStrokeColorWithColor(context, [self getCurrentColor]);
|
||||
strokeColor = YES;
|
||||
} else {
|
||||
strokeColor = [self.stroke applyStrokeColor:context opacity:self.strokeOpacity];
|
||||
@@ -724,6 +725,7 @@ UInt32 saturate(CGFloat value)
|
||||
|
||||
- (void)mergeProperties:(__kindof RNSVGRenderable *)target
|
||||
{
|
||||
_caller = target;
|
||||
NSArray<NSString *> *targetAttributeList = [target getAttributeList];
|
||||
|
||||
if (targetAttributeList.count == 0) {
|
||||
@@ -754,9 +756,28 @@ UInt32 saturate(CGFloat value)
|
||||
[self setValue:[_originProperties valueForKey:key] forKey:key];
|
||||
}
|
||||
|
||||
_caller = nil;
|
||||
_lastMergedList = nil;
|
||||
_attributeList = _propList;
|
||||
self.merging = false;
|
||||
}
|
||||
|
||||
- (CGColor *)getCurrentColor
|
||||
{
|
||||
if (self.color != nil) {
|
||||
return [self.color CGColor];
|
||||
}
|
||||
if (_caller != nil) {
|
||||
return [_caller getCurrentColor];
|
||||
}
|
||||
RNSVGPlatformView *parentView = [self superview];
|
||||
if ([parentView isKindOfClass:[RNSVGRenderable class]]) {
|
||||
return [(RNSVGRenderable *)parentView getCurrentColor];
|
||||
} else if ([parentView isKindOfClass:[RNSVGSvgView class]]) {
|
||||
return [[(RNSVGSvgView *)parentView color] CGColor];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#import "RNSVGUIKit.h"
|
||||
|
||||
@implementation RNSVGView {
|
||||
NSColor *_tintColor;
|
||||
}
|
||||
|
||||
- (CGPoint)center
|
||||
@@ -20,29 +19,6 @@
|
||||
self.frame = CGRectMake(xOrigin, yOrigin, frameRect.size.width, frameRect.size.height);
|
||||
}
|
||||
|
||||
- (NSColor *)tintColor
|
||||
{
|
||||
if (_tintColor != nil) {
|
||||
return _tintColor;
|
||||
}
|
||||
|
||||
// To mimic iOS's tintColor, we crawl up the view hierarchy until either:
|
||||
// (a) we find a valid color
|
||||
// (b) we reach a view that isn't an RNSVGView
|
||||
NSView *parentView = [self superview];
|
||||
if ([parentView isKindOfClass:[RNSVGView class]]) {
|
||||
return [(RNSVGView *)parentView tintColor];
|
||||
} else {
|
||||
return [NSColor controlAccentColor];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setTintColor:(NSColor *)tintColor
|
||||
{
|
||||
_tintColor = tintColor;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSImage (RNSVGMacOSExtensions)
|
||||
|
||||
@@ -133,7 +133,7 @@ using namespace facebook::react;
|
||||
if (self.inlineSize != nil && self.inlineSize.value != 0) {
|
||||
if (self.fill) {
|
||||
if (self.fill.class == RNSVGBrush.class) {
|
||||
CGColorRef color = [self.tintColor CGColor];
|
||||
CGColorRef color = [self getCurrentColor];
|
||||
[self drawWrappedText:context gc:gc rect:rect color:color];
|
||||
} else {
|
||||
CGColorRef color = [self.fill getColorWithOpacity:self.fillOpacity];
|
||||
@@ -143,7 +143,7 @@ using namespace facebook::react;
|
||||
}
|
||||
if (self.stroke) {
|
||||
if (self.stroke.class == RNSVGBrush.class) {
|
||||
CGColorRef color = [self.tintColor CGColor];
|
||||
CGColorRef color = [self getCurrentColor];
|
||||
[self drawWrappedText:context gc:gc rect:rect color:color];
|
||||
} else {
|
||||
CGColorRef color = [self.stroke getColorWithOpacity:self.strokeOpacity];
|
||||
|
||||
@@ -24,7 +24,7 @@ RCT_EXPORT_MODULE()
|
||||
return [RNSVGRenderable new];
|
||||
}
|
||||
|
||||
RCT_REMAP_VIEW_PROPERTY(color, tintColor, UIColor)
|
||||
RCT_EXPORT_VIEW_PROPERTY(color, UIColor)
|
||||
RCT_EXPORT_VIEW_PROPERTY(fill, RNSVGBrush)
|
||||
RCT_EXPORT_VIEW_PROPERTY(fillOpacity, CGFloat)
|
||||
RCT_EXPORT_VIEW_PROPERTY(fillRule, RNSVGCGFCRule)
|
||||
|
||||
@@ -26,7 +26,7 @@ RCT_EXPORT_VIEW_PROPERTY(vbWidth, CGFloat)
|
||||
RCT_EXPORT_VIEW_PROPERTY(vbHeight, CGFloat)
|
||||
RCT_EXPORT_VIEW_PROPERTY(align, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(meetOrSlice, RNSVGVBMOS)
|
||||
RCT_REMAP_VIEW_PROPERTY(color, tintColor, UIColor)
|
||||
RCT_EXPORT_VIEW_PROPERTY(color, UIColor)
|
||||
RCT_CUSTOM_VIEW_PROPERTY(hitSlop, UIEdgeInsets, RNSVGSvgView)
|
||||
{
|
||||
if ([view respondsToSelector:@selector(setHitTestEdgeInsets:)]) {
|
||||
|
||||
Reference in New Issue
Block a user