mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-06 07:06:11 +00:00
feat: use dynamics instead of strings for props that can be either string or number (#2238)
# Summary PR bringing proper support for react-native-reanimated in the library by using dynamics instead of strings for props that can be either string or number.
This commit is contained in:
@@ -10,6 +10,50 @@
|
||||
#import <React/RCTConversions.h>
|
||||
#import <React/RCTFabricComponentsPlugins.h>
|
||||
|
||||
#import <folly/dynamic.h>
|
||||
|
||||
// copied from RCTFollyConvert
|
||||
static id RNSVGConvertFollyDynamicToId(const folly::dynamic &dyn)
|
||||
{
|
||||
// I could imagine an implementation which avoids copies by wrapping the
|
||||
// dynamic in a derived class of NSDictionary. We can do that if profiling
|
||||
// implies it will help.
|
||||
|
||||
switch (dyn.type()) {
|
||||
case folly::dynamic::NULLT:
|
||||
return nil;
|
||||
case folly::dynamic::BOOL:
|
||||
return dyn.getBool() ? @YES : @NO;
|
||||
case folly::dynamic::INT64:
|
||||
return @(dyn.getInt());
|
||||
case folly::dynamic::DOUBLE:
|
||||
return @(dyn.getDouble());
|
||||
case folly::dynamic::STRING:
|
||||
return [[NSString alloc] initWithBytes:dyn.c_str() length:dyn.size() encoding:NSUTF8StringEncoding];
|
||||
case folly::dynamic::ARRAY: {
|
||||
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:dyn.size()];
|
||||
for (const auto &elem : dyn) {
|
||||
id value = RNSVGConvertFollyDynamicToId(elem);
|
||||
if (value) {
|
||||
[array addObject:value];
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
case folly::dynamic::OBJECT: {
|
||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:dyn.size()];
|
||||
for (const auto &elem : dyn.items()) {
|
||||
id key = RNSVGConvertFollyDynamicToId(elem.first);
|
||||
id value = RNSVGConvertFollyDynamicToId(elem.second);
|
||||
if (key && value) {
|
||||
dict[key] = value;
|
||||
}
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
RNSVGBrush *brushFromColorStruct(const T &fillObject)
|
||||
{
|
||||
@@ -87,19 +131,6 @@ void setCommonNodeProps(const T &nodeProps, RNSVGNode *node)
|
||||
node.accessibilityLabel = RCTNSStringFromStringNilIfEmpty(nodeProps.accessibilityLabel);
|
||||
}
|
||||
|
||||
static NSMutableArray<RNSVGLength *> *createLengthArrayFromStrings(const std::vector<std::string> &stringArray)
|
||||
{
|
||||
if (stringArray.empty()) {
|
||||
return nil;
|
||||
}
|
||||
NSMutableArray<RNSVGLength *> *lengthArray = [NSMutableArray new];
|
||||
for (auto str : stringArray) {
|
||||
RNSVGLength *lengthFromString = [RNSVGLength lengthWithString:RCTNSStringFromString(str)];
|
||||
[lengthArray addObject:lengthFromString];
|
||||
}
|
||||
return lengthArray;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void setCommonRenderableProps(const T &renderableProps, RNSVGRenderable *renderableNode)
|
||||
{
|
||||
@@ -109,14 +140,20 @@ void setCommonRenderableProps(const T &renderableProps, RNSVGRenderable *rendera
|
||||
renderableNode.fillRule = renderableProps.fillRule == 0 ? kRNSVGCGFCRuleEvenodd : kRNSVGCGFCRuleNonzero;
|
||||
renderableNode.stroke = brushFromColorStruct(renderableProps.stroke);
|
||||
renderableNode.strokeOpacity = renderableProps.strokeOpacity;
|
||||
renderableNode.strokeWidth = [RNSVGLength lengthWithString:RCTNSStringFromString(renderableProps.strokeWidth)];
|
||||
id strokeWidth = RNSVGConvertFollyDynamicToId(renderableProps.strokeWidth);
|
||||
if (strokeWidth != nil) {
|
||||
renderableNode.strokeWidth = [RCTConvert RNSVGLength:strokeWidth];
|
||||
}
|
||||
renderableNode.strokeLinecap = renderableProps.strokeLinecap == 0 ? kCGLineCapButt
|
||||
: renderableProps.strokeLinecap == 1 ? kCGLineCapRound
|
||||
: kCGLineCapSquare;
|
||||
renderableNode.strokeLinejoin = renderableProps.strokeLinejoin == 0 ? kCGLineJoinMiter
|
||||
: renderableProps.strokeLinejoin == 1 ? kCGLineJoinRound
|
||||
: kCGLineJoinBevel;
|
||||
renderableNode.strokeDasharray = createLengthArrayFromStrings(renderableProps.strokeDasharray);
|
||||
id strokeDasharray = RNSVGConvertFollyDynamicToId(renderableProps.strokeDasharray);
|
||||
if (strokeDasharray != nil) {
|
||||
renderableNode.strokeDasharray = [RCTConvert RNSVGLengthArray:strokeDasharray];
|
||||
}
|
||||
renderableNode.strokeDashoffset = renderableProps.strokeDashoffset;
|
||||
renderableNode.strokeMiterlimit = renderableProps.strokeMiterlimit;
|
||||
renderableNode.vectorEffect = renderableProps.vectorEffect == 0 ? kRNSVGVectorEffectDefault
|
||||
@@ -132,53 +169,27 @@ void setCommonRenderableProps(const T &renderableProps, RNSVGRenderable *rendera
|
||||
}
|
||||
}
|
||||
|
||||
static void addValueToDict(NSMutableDictionary *dict, const std::string &value, NSString *key)
|
||||
{
|
||||
NSString *valueOrNil = RCTNSStringFromStringNilIfEmpty(value);
|
||||
if (valueOrNil) {
|
||||
dict[key] = valueOrNil;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
NSDictionary *parseFontStruct(const T &fontStruct)
|
||||
{
|
||||
NSMutableDictionary *fontDict = [NSMutableDictionary new];
|
||||
|
||||
// TODO: do it better maybe
|
||||
addValueToDict(fontDict, fontStruct.fontStyle, @"fontStyle");
|
||||
addValueToDict(fontDict, fontStruct.fontVariant, @"fontVariant");
|
||||
addValueToDict(fontDict, fontStruct.fontWeight, @"fontWeight");
|
||||
addValueToDict(fontDict, fontStruct.fontStretch, @"fontStretch");
|
||||
addValueToDict(fontDict, fontStruct.fontSize, @"fontSize");
|
||||
addValueToDict(fontDict, fontStruct.fontFamily, @"fontFamily");
|
||||
addValueToDict(fontDict, fontStruct.textAnchor, @"textAnchor");
|
||||
addValueToDict(fontDict, fontStruct.textDecoration, @"textDecoration");
|
||||
addValueToDict(fontDict, fontStruct.letterSpacing, @"letterSpacing");
|
||||
addValueToDict(fontDict, fontStruct.wordSpacing, @"wordSpacing");
|
||||
addValueToDict(fontDict, fontStruct.kerning, @"kerning");
|
||||
addValueToDict(fontDict, fontStruct.fontFeatureSettings, @"fontFeatureSettings");
|
||||
addValueToDict(fontDict, fontStruct.fontVariantLigatures, @"fontVariantLigatures");
|
||||
addValueToDict(fontDict, fontStruct.fontVariationSettings, @"fontVariationSettings");
|
||||
return [NSDictionary dictionaryWithDictionary:fontDict];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void setCommonGroupProps(const T &groupProps, RNSVGGroup *groupNode)
|
||||
{
|
||||
setCommonRenderableProps(groupProps, groupNode);
|
||||
|
||||
if (RCTNSStringFromStringNilIfEmpty(groupProps.fontSize)) {
|
||||
groupNode.font = @{@"fontSize" : RCTNSStringFromString(groupProps.fontSize)};
|
||||
id fontSize = RNSVGConvertFollyDynamicToId(groupProps.fontSize);
|
||||
if (fontSize != nil) {
|
||||
groupNode.font = @{@"fontSize" : fontSize};
|
||||
}
|
||||
if (RCTNSStringFromStringNilIfEmpty(groupProps.fontWeight)) {
|
||||
groupNode.font = @{@"fontWeight" : RCTNSStringFromString(groupProps.fontWeight)};
|
||||
id fontWeight = RNSVGConvertFollyDynamicToId(groupProps.fontWeight);
|
||||
if (fontWeight != nil) {
|
||||
groupNode.font = @{@"fontWeight" : fontWeight};
|
||||
}
|
||||
NSDictionary *fontDict = parseFontStruct(groupProps.font);
|
||||
if (groupNode.font == nil || fontDict.count > 0) {
|
||||
// some of text's rendering logic requires that `font` is not nil so we always set it
|
||||
// even if to an empty dict
|
||||
groupNode.font = fontDict;
|
||||
id font = RNSVGConvertFollyDynamicToId(groupProps.font);
|
||||
if (font != nil) {
|
||||
NSDictionary *fontDict = (NSDictionary *)font;
|
||||
if (groupNode.font == nil || fontDict.count > 0) {
|
||||
// some of text's rendering logic requires that `font` is not nil so we always set it
|
||||
// even if to an empty dict
|
||||
groupNode.font = fontDict;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,18 +197,43 @@ template <typename T>
|
||||
void setCommonTextProps(const T &textProps, RNSVGText *textNode)
|
||||
{
|
||||
setCommonGroupProps(textProps, textNode);
|
||||
textNode.deltaX = createLengthArrayFromStrings(textProps.dx);
|
||||
textNode.deltaY = createLengthArrayFromStrings(textProps.dy);
|
||||
if (!textProps.x.empty()) {
|
||||
textNode.positionX = createLengthArrayFromStrings(textProps.x);
|
||||
id deltaX = RNSVGConvertFollyDynamicToId(textProps.dx);
|
||||
if (deltaX != nil) {
|
||||
textNode.deltaX = [RCTConvert RNSVGLengthArray:deltaX];
|
||||
}
|
||||
if (!textProps.y.empty()) {
|
||||
textNode.positionY = createLengthArrayFromStrings(textProps.y);
|
||||
id deltaY = RNSVGConvertFollyDynamicToId(textProps.dy);
|
||||
if (deltaY != nil) {
|
||||
textNode.deltaY = [RCTConvert RNSVGLengthArray:deltaY];
|
||||
}
|
||||
id positionX = RNSVGConvertFollyDynamicToId(textProps.x);
|
||||
if (positionX != nil) {
|
||||
textNode.positionX = [RCTConvert RNSVGLengthArray:positionX];
|
||||
}
|
||||
id positionY = RNSVGConvertFollyDynamicToId(textProps.y);
|
||||
if (positionY != nil) {
|
||||
textNode.positionY = [RCTConvert RNSVGLengthArray:positionY];
|
||||
}
|
||||
id rotate = RNSVGConvertFollyDynamicToId(textProps.rotate);
|
||||
if (rotate != nil) {
|
||||
textNode.rotate = [RCTConvert RNSVGLengthArray:rotate];
|
||||
}
|
||||
id textLength = RNSVGConvertFollyDynamicToId(textProps.textLength);
|
||||
if (textLength != nil) {
|
||||
textNode.textLength = [RCTConvert RNSVGLength:textLength];
|
||||
}
|
||||
id inlineSize = RNSVGConvertFollyDynamicToId(textProps.inlineSize);
|
||||
if (inlineSize != nil) {
|
||||
textNode.inlineSize = [RCTConvert RNSVGLength:inlineSize];
|
||||
}
|
||||
id baselineShift = RNSVGConvertFollyDynamicToId(textProps.baselineShift);
|
||||
if (baselineShift != nil) {
|
||||
if ([baselineShift isKindOfClass:[NSString class]]) {
|
||||
NSString *stringValue = (NSString *)baselineShift;
|
||||
textNode.baselineShift = stringValue;
|
||||
} else {
|
||||
textNode.baselineShift = [NSString stringWithFormat:@"%f", [baselineShift doubleValue]];
|
||||
}
|
||||
}
|
||||
textNode.rotate = createLengthArrayFromStrings(textProps.rotate);
|
||||
textNode.inlineSize = [RNSVGLength lengthWithString:RCTNSStringFromString(textProps.inlineSize)];
|
||||
textNode.textLength = [RNSVGLength lengthWithString:RCTNSStringFromString(textProps.textLength)];
|
||||
textNode.baselineShift = RCTNSStringFromStringNilIfEmpty(textProps.baselineShift);
|
||||
textNode.lengthAdjust = RCTNSStringFromStringNilIfEmpty(textProps.lengthAdjust);
|
||||
textNode.alignmentBaseline = RCTNSStringFromStringNilIfEmpty(textProps.alignmentBaseline);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user