Added explicit types for all view properties

This commit is contained in:
Nick Lockwood 2015-03-25 21:29:28 -07:00
parent 558b8c65e0
commit 19e328fb08
32 changed files with 436 additions and 533 deletions

View File

@ -93,9 +93,24 @@
}
};
} else {
share.completionHandler = ^(NSString *activityType, BOOL completed) {
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
};
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
if (![UIActivityViewController instancesRespondToSelector:@selector(completionWithItemsHandler)]) {
// Legacy iOS 7 implementation
share.completionHandler = ^(NSString *activityType, BOOL completed) {
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
};
} else
#endif
{
// iOS 8 version
share.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
};
}
}
[ctrl presentViewController:share animated:YES completion:nil];
});

View File

@ -83,7 +83,7 @@
} else if ([obj respondsToSelector:@selector(count)]) {
switch ([obj count]) {
case 2:
if ([obj respondsToSelector:@selector(objectForKeyedSubscript:)] && obj[@"x"]) {
if (![obj respondsToSelector:@selector(objectForKeyedSubscript:)] || obj[@"x"]) {
toValue = [NSValue valueWithCGPoint:[RCTConvert CGPoint:obj]];
} else {
toValue = [NSValue valueWithCGSize:[RCTConvert CGSize:obj]];
@ -192,9 +192,9 @@
UIView *view = viewRegistry[reactTag];
for (NSString *animationKey in view.layer.animationKeys) {
if ([animationKey hasPrefix:@"RCT"]) {
NSRange periodLocation = [animationKey rangeOfString:@"." options:0 range:NSMakeRange(3, animationKey.length - 3)];
NSRange periodLocation = [animationKey rangeOfString:@"." options:0 range:(NSRange){3, animationKey.length - 3}];
if (periodLocation.location != NSNotFound) {
NSInteger integerTag = [[animationKey substringWithRange:NSMakeRange(3, periodLocation.location)] integerValue];
NSInteger integerTag = [[animationKey substringWithRange:(NSRange){3, periodLocation.location}] integerValue];
if (animationTag.integerValue == integerTag) {
[view.layer removeAnimationForKey:animationKey];
}

View File

@ -35,14 +35,25 @@ var SliderIOS = React.createClass({
style: View.propTypes.style,
/**
* Initial value of the slider. The value should be between 0 and 1.
* Initial value of the slider. The value should be between minimumValue
* and maximumValue, which default to 0 and 1 respectively.
* Default value is 0.
*
* *This is not a controlled component*, e.g. if you don't update
* the value, the component won't be reseted to it's inital value.
* the value, the component won't be reset to it's inital value.
*/
value: PropTypes.number,
/**
* Initial minimum value of the slider. Default value is 0.
*/
minimumValue: PropTypes.number,
/**
* Initial maximum value of the slider. Default value is 1.
*/
maximumValue: PropTypes.number,
/**
* Callback continuously called while the user is dragging the slider.
*/

View File

@ -39,7 +39,9 @@ var RCTTextViewAttributes = merge(ReactIOSViewAttributes.UIView, {
autoCapitalize: true,
color: true,
editable: true,
fontFamily: true,
fontSize: true,
fontStyle: true,
fontWeight: true,
keyboardType: true,
mostRecentEventCounter: true,

View File

@ -25,8 +25,8 @@
return view;
}
RCT_REMAP_VIEW_PROPERTY(defaultImageSrc, defaultImage)
RCT_REMAP_VIEW_PROPERTY(src, imageURL)
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode)
RCT_REMAP_VIEW_PROPERTY(defaultImageSrc, defaultImage, UIImage)
RCT_REMAP_VIEW_PROPERTY(src, imageURL, NSURL)
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
@end

View File

@ -23,9 +23,9 @@
return [[RCTStaticImage alloc] init];
}
RCT_EXPORT_VIEW_PROPERTY(capInsets)
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode)
RCT_CUSTOM_VIEW_PROPERTY(src, RCTStaticImage)
RCT_EXPORT_VIEW_PROPERTY(capInsets, UIEdgeInsets)
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
RCT_CUSTOM_VIEW_PROPERTY(src, NSURL, RCTStaticImage)
{
if (json) {
if ([[[json description] pathExtension] caseInsensitiveCompare:@"gif"] == NSOrderedSame) {
@ -37,7 +37,7 @@ RCT_CUSTOM_VIEW_PROPERTY(src, RCTStaticImage)
view.image = defaultView.image;
}
}
RCT_CUSTOM_VIEW_PROPERTY(tintColor, RCTStaticImage)
RCT_CUSTOM_VIEW_PROPERTY(tintColor, UIColor, RCTStaticImage)
{
if (json) {
view.renderingMode = UIImageRenderingModeAlwaysTemplate;
@ -47,15 +47,14 @@ RCT_CUSTOM_VIEW_PROPERTY(tintColor, RCTStaticImage)
view.tintColor = defaultView.tintColor;
}
}
RCT_CUSTOM_VIEW_PROPERTY(imageTag, RCTStaticImage)
RCT_CUSTOM_VIEW_PROPERTY(imageTag, NSString, RCTStaticImage)
{
if (json) {
[RCTImageLoader loadImageWithTag:[RCTConvert NSString:json] callback:^(NSError *error, UIImage *image) {
if (error) {
RCTLogWarn(@"%@", error.localizedDescription);
} else {
view.image = image;
}
view.image = image;
}];
} else {
view.image = defaultView.image;

View File

@ -23,5 +23,7 @@
return [[RCTShadowRawText alloc] init];
}
RCT_EXPORT_SHADOW_PROPERTY(text, NSString)
@end

View File

@ -17,7 +17,6 @@ extern NSString *const RCTReactTagAttributeName;
@property (nonatomic, assign) NSWritingDirection writingDirection;
@property (nonatomic, strong) UIColor *textBackgroundColor;
@property (nonatomic, strong) UIColor *color;
@property (nonatomic, strong) UIFont *font;
@property (nonatomic, copy) NSString *fontFamily;
@property (nonatomic, assign) CGFloat fontSize;
@property (nonatomic, copy) NSString *fontWeight;
@ -27,6 +26,9 @@ extern NSString *const RCTReactTagAttributeName;
@property (nonatomic, assign) NSInteger maxNumberOfLines;
@property (nonatomic, assign) CGSize shadowOffset;
@property (nonatomic, assign) NSTextAlignment textAlign;
// Not exposed to JS
@property (nonatomic, strong) UIFont *font;
@property (nonatomic, assign) NSLineBreakMode truncationMode;
- (NSAttributedString *)attributedString;

View File

@ -11,7 +11,6 @@
#import "RCTConvert.h"
#import "RCTLog.h"
#import "RCTShadowRawText.h"
#import "RCTUtils.h"
@ -154,7 +153,7 @@ static css_dim_t RCTMeasure(void *context, float width)
}
}];
// TODO: umm, these can'e be null, so we're mapping left to natural - is that right?
// TODO: umm, these can't be null, so we're mapping left to natural - is that right?
self.textAlign = _textAlign ?: NSTextAlignmentNatural;
self.writingDirection = _writingDirection ?: NSWritingDirectionNatural;

View File

@ -32,8 +32,8 @@
#pragma mark - View properties
RCT_REMAP_VIEW_PROPERTY(containerBackgroundColor, backgroundColor)
RCT_CUSTOM_VIEW_PROPERTY(numberOfLines, RCTText)
RCT_REMAP_VIEW_PROPERTY(containerBackgroundColor, backgroundColor, UIColor)
RCT_CUSTOM_VIEW_PROPERTY(numberOfLines, NSInteger, RCTText)
{
NSLineBreakMode truncationMode = NSLineBreakByClipping;
view.numberOfLines = json ? [RCTConvert NSInteger:json] : defaultView.numberOfLines;
@ -45,16 +45,24 @@ RCT_CUSTOM_VIEW_PROPERTY(numberOfLines, RCTText)
#pragma mark - Shadow properties
RCT_CUSTOM_SHADOW_PROPERTY(backgroundColor, RCTShadowText)
{
view.textBackgroundColor = json ? [RCTConvert UIColor:json] : defaultView.textBackgroundColor;
}
RCT_CUSTOM_SHADOW_PROPERTY(containerBackgroundColor, RCTShadowText)
RCT_EXPORT_SHADOW_PROPERTY(writingDirection, NSWritingDirection)
RCT_EXPORT_SHADOW_PROPERTY(color, UIColor)
RCT_EXPORT_SHADOW_PROPERTY(fontFamily, NSString)
RCT_EXPORT_SHADOW_PROPERTY(fontSize, CGFloat)
RCT_EXPORT_SHADOW_PROPERTY(fontWeight, NSString)
RCT_EXPORT_SHADOW_PROPERTY(fontStyle, NSString)
RCT_EXPORT_SHADOW_PROPERTY(isHighlighted, BOOL)
RCT_EXPORT_SHADOW_PROPERTY(lineHeight, CGFloat)
RCT_EXPORT_SHADOW_PROPERTY(maxNumberOfLines, NSInteger)
RCT_EXPORT_SHADOW_PROPERTY(shadowOffset, CGSize)
RCT_EXPORT_SHADOW_PROPERTY(textAlign, NSTextAlignment)
RCT_REMAP_SHADOW_PROPERTY(backgroundColor, textBackgroundColor, UIColor)
RCT_CUSTOM_SHADOW_PROPERTY(containerBackgroundColor, UIColor, RCTShadowText)
{
view.backgroundColor = json ? [RCTConvert UIColor:json] : defaultView.backgroundColor;
view.isBGColorExplicitlySet = json ? YES : defaultView.isBGColorExplicitlySet;
}
RCT_CUSTOM_SHADOW_PROPERTY(numberOfLines, RCTShadowText)
RCT_CUSTOM_SHADOW_PROPERTY(numberOfLines, NSInteger, RCTShadowText)
{
NSLineBreakMode truncationMode = NSLineBreakByClipping;
view.maxNumberOfLines = json ? [RCTConvert NSInteger:json] : defaultView.maxNumberOfLines;
@ -63,10 +71,6 @@ RCT_CUSTOM_SHADOW_PROPERTY(numberOfLines, RCTShadowText)
}
view.truncationMode = truncationMode;
}
RCT_CUSTOM_SHADOW_PROPERTY(textAlign, RCTShadowText)
{
view.textAlign = json ? [RCTConvert NSTextAlignment:json] : defaultView.textAlign;
}
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(RCTShadowText *)shadowView
{

View File

@ -48,8 +48,13 @@
+ (NSTextAlignment)NSTextAlignment:(id)json;
+ (NSWritingDirection)NSWritingDirection:(id)json;
+ (UITextAutocapitalizationType)UITextAutocapitalizationType:(id)json;
+ (UITextFieldViewMode)UITextFieldViewMode:(id)json;
+ (UIScrollViewKeyboardDismissMode)UIScrollViewKeyboardDismissMode:(id)json;
+ (UIKeyboardType)UIKeyboardType:(id)json;
+ (UIViewContentMode)UIViewContentMode:(id)json;
+ (UIBarStyle)UIBarStyle:(id)json;
+ (CGFloat)CGFloat:(id)json;
+ (CGPoint)CGPoint:(id)json;
+ (CGSize)CGSize:(id)json;
@ -72,13 +77,11 @@
+ (UIFont *)UIFont:(UIFont *)font withWeight:(id)json;
+ (UIFont *)UIFont:(UIFont *)font withStyle:(id)json;
+ (UIFont *)UIFont:(UIFont *)font withFamily:(id)json;
+ (UIFont *)UIFont:(UIFont *)font
withFamily:(id)family
size:(id)size
weight:(id)weight
style:(id)style;
+ (UIFont *)UIFont:(UIFont *)font withFamily:(id)family
size:(id)size weight:(id)weight style:(id)style;
+ (NSArray *)NSStringArray:(id)json;
+ (NSArray *)NSDictionaryArray:(id)json;
+ (NSArray *)NSURLArray:(id)json;
+ (NSArray *)NSNumberArray:(id)json;
+ (NSArray *)UIColorArray:(id)json;
@ -106,20 +109,14 @@ extern "C" {
* applying an appropriate conversion method. If the property does not
* exist, or the type cannot be inferred, the function will return NO.
*/
BOOL RCTSetProperty(id target, NSString *keypath, id json);
BOOL RCTSetProperty(id target, NSString *keyPath, SEL type, id json);
/**
* This function attempts to copy a property from the source object to the
* destination object using KVC. If the property does not exist, or cannot
* be set, it will do nothing and return NO.
*/
BOOL RCTCopyProperty(id target, id source, NSString *keypath);
/**
* This function attempts to convert a JSON value to an object that can be used
* in KVC with the specific target and key path.
*/
id RCTConvertValue(id target, NSString *keypath, id json);
BOOL RCTCopyProperty(id target, id source, NSString *keyPath);
#ifdef __cplusplus
}

View File

@ -102,11 +102,45 @@ RCT_ENUM_CONVERTER(UITextAutocapitalizationType, (@{
@"characters": @(UITextAutocapitalizationTypeAllCharacters)
}), UITextAutocapitalizationTypeSentences, integerValue)
RCT_ENUM_CONVERTER(UITextFieldViewMode, (@{
@"never": @(UITextFieldViewModeNever),
@"while-editing": @(UITextFieldViewModeWhileEditing),
@"unless-editing": @(UITextFieldViewModeUnlessEditing),
@"always": @(UITextFieldViewModeAlways),
}), UITextFieldViewModeNever, integerValue)
RCT_ENUM_CONVERTER(UIScrollViewKeyboardDismissMode, (@{
@"none": @(UIScrollViewKeyboardDismissModeNone),
@"on-drag": @(UIScrollViewKeyboardDismissModeOnDrag),
@"interactive": @(UIScrollViewKeyboardDismissModeInteractive),
}), UIScrollViewKeyboardDismissModeNone, integerValue)
RCT_ENUM_CONVERTER(UIKeyboardType, (@{
@"numeric": @(UIKeyboardTypeDecimalPad),
@"default": @(UIKeyboardTypeDefault),
}), UIKeyboardTypeDefault, integerValue)
RCT_ENUM_CONVERTER(UIViewContentMode, (@{
@"scale-to-fill": @(UIViewContentModeScaleToFill),
@"scale-aspect-fit": @(UIViewContentModeScaleAspectFit),
@"scale-aspect-fill": @(UIViewContentModeScaleAspectFill),
@"redraw": @(UIViewContentModeRedraw),
@"center": @(UIViewContentModeCenter),
@"top": @(UIViewContentModeTop),
@"bottom": @(UIViewContentModeBottom),
@"left": @(UIViewContentModeLeft),
@"right": @(UIViewContentModeRight),
@"top-left": @(UIViewContentModeTopLeft),
@"top-right": @(UIViewContentModeTopRight),
@"bottom-left": @(UIViewContentModeBottomLeft),
@"bottom-right": @(UIViewContentModeBottomRight),
}), UIViewContentModeScaleToFill, integerValue)
RCT_ENUM_CONVERTER(UIBarStyle, (@{
@"default": @(UIBarStyleDefault),
@"black": @(UIBarStyleBlack),
}), UIBarStyleDefault, integerValue)
// TODO: normalise the use of w/width so we can do away with the alias values (#6566645)
RCT_CONVERTER_CUSTOM(CGFloat, CGFloat, [self double:json])
RCT_CGSTRUCT_CONVERTER(CGPoint, (@[@"x", @"y"]), nil)
@ -500,11 +534,8 @@ static BOOL RCTFontIsCondensed(UIFont *font)
return [self UIFont:font withFamily:json size:nil weight:nil style:nil];
}
+ (UIFont *)UIFont:(UIFont *)font
withFamily:(id)family
size:(id)size
weight:(id)weight
style:(id)style
+ (UIFont *)UIFont:(UIFont *)font withFamily:(id)family
size:(id)size weight:(id)weight style:(id)style
{
// Defaults
NSString *const RCTDefaultFontFamily = @"Helvetica Neue";
@ -579,6 +610,7 @@ static BOOL RCTFontIsCondensed(UIFont *font)
}
RCT_ARRAY_CONVERTER(NSString)
RCT_ARRAY_CONVERTER(NSDictionary)
RCT_ARRAY_CONVERTER(NSURL)
RCT_ARRAY_CONVERTER(NSNumber)
RCT_ARRAY_CONVERTER(UIColor)
@ -648,229 +680,10 @@ RCT_ENUM_CONVERTER(RCTAnimationType, (@{
@end
static NSString *RCTGuessTypeEncoding(id target, NSString *key, id value, NSString *encoding)
{
/**
* NOTE: the property names below may seem weird, but it's
* because they are tested as case-sensitive suffixes, so
* "ffset" will match any of the following
*
* - offset
* - contentOffset
*/
// TODO (#5906496): handle more cases
if ([key hasSuffix:@"olor"]) {
if ([target isKindOfClass:[CALayer class]]) {
return @(@encode(CGColorRef));
} else {
return @"@\"UIColor\"";
}
} else if ([key hasSuffix:@"Inset"] || [key hasSuffix:@"Insets"]) {
return @(@encode(UIEdgeInsets));
} else if ([key hasSuffix:@"rame"] || [key hasSuffix:@"ounds"]) {
return @(@encode(CGRect));
} else if ([key hasSuffix:@"ffset"] || [key hasSuffix:@"osition"]) {
return @(@encode(CGPoint));
} else if ([key hasSuffix:@"ize"]) {
return @(@encode(CGSize));
}
return nil;
}
static id RCTConvertValueWithEncoding(id value, NSString *encoding)
{
static NSDictionary *converters = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
id (^numberConvert)(id) = ^(id val){
return [RCTConvert NSNumber:val];
};
id (^boolConvert)(id) = ^(id val){
return @([RCTConvert BOOL:val]);
};
// TODO (#5906496): add the rest of RCTConvert here
converters =
@{
@(@encode(char)): boolConvert,
@(@encode(int)): numberConvert,
@(@encode(short)): numberConvert,
@(@encode(long)): numberConvert,
@(@encode(long long)): numberConvert,
@(@encode(unsigned char)): numberConvert,
@(@encode(unsigned int)): numberConvert,
@(@encode(unsigned short)): numberConvert,
@(@encode(unsigned long)): numberConvert,
@(@encode(unsigned long long)): numberConvert,
@(@encode(float)): numberConvert,
@(@encode(double)): numberConvert,
@(@encode(bool)): boolConvert,
@(@encode(UIEdgeInsets)): ^(id val) {
return [NSValue valueWithUIEdgeInsets:[RCTConvert UIEdgeInsets:val]];
},
@(@encode(CGPoint)): ^(id val) {
return [NSValue valueWithCGPoint:[RCTConvert CGPoint:val]];
},
@(@encode(CGSize)): ^(id val) {
return [NSValue valueWithCGSize:[RCTConvert CGSize:val]];
},
@(@encode(CGRect)): ^(id val) {
return [NSValue valueWithCGRect:[RCTConvert CGRect:val]];
},
@(@encode(CGColorRef)): ^(id val) {
return (id)[RCTConvert CGColor:val];
},
@(@encode(CGAffineTransform)): ^(id val) {
return [NSValue valueWithCGAffineTransform:[RCTConvert CGAffineTransform:val]];
},
@(@encode(CATransform3D)): ^(id val) {
return [NSValue valueWithCATransform3D:[RCTConvert CATransform3D:val]];
},
@"@\"NSString\"": ^(id val) {
return [RCTConvert NSString:val];
},
@"@\"NSURL\"": ^(id val) {
return [RCTConvert NSURL:val];
},
@"@\"UIColor\"": ^(id val) {
return [RCTConvert UIColor:val];
},
@"@\"UIImage\"": ^(id val) {
return [RCTConvert UIImage:val];
},
@"@\"NSDate\"": ^(id val) {
return [RCTConvert NSDate:val];
},
@"@\"NSTimeZone\"": ^(id val) {
return [RCTConvert NSTimeZone:val];
},
};
});
// Handle null values
if (value == [NSNull null] && ![encoding isEqualToString:@"@\"NSNull\""]) {
return nil;
}
// Convert value
id (^converter)(id) = converters[encoding];
return converter ? converter(value) : value;
}
static NSString *RCTPropertyEncoding(id target, NSString *key, id value)
{
// Check target class for property definition
NSString *encoding = nil;
objc_property_t property = class_getProperty([target class], [key UTF8String]);
if (property) {
// Get type info
char *typeEncoding = property_copyAttributeValue(property, "T");
encoding = @(typeEncoding);
free(typeEncoding);
} else {
// Check if setter exists
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",
[[key substringToIndex:1] uppercaseString],
[key substringFromIndex:1]]);
if (![target respondsToSelector:setter]) {
return nil;
}
// Get type of first method argument
Method method = class_getInstanceMethod([target class], setter);
char *typeEncoding = method_copyArgumentType(method, 2);
if (typeEncoding) {
encoding = @(typeEncoding);
free(typeEncoding);
}
if (encoding.length == 0 || [encoding isEqualToString:@(@encode(id))]) {
// Not enough info about the type encoding to be useful, so
// try to guess the type from the value and property name
encoding = RCTGuessTypeEncoding(target, key, value, encoding);
}
}
// id encoding means unknown, as opposed to nil which means no setter exists.
return encoding ?: @(@encode(id));
}
static id RCTConvertValueWithExplicitEncoding(id target, NSString *key, id json, NSString *encoding)
{
// Special case for numeric encodings, which may be enums
if ([json isKindOfClass:[NSString class]] &&
([encoding isEqualToString:@(@encode(id))] ||
[@"iIsSlLqQ" rangeOfString:[encoding substringToIndex:1]].length)) {
/**
* NOTE: the property names below may seem weird, but it's
* because they are tested as case-sensitive suffixes, so
* "apitalizationType" will match any of the following
*
* - capitalizationType
* - autocapitalizationType
* - autoCapitalizationType
* - titleCapitalizationType
* - etc.
*/
static NSDictionary *converters = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
converters =
@{
@"apitalizationType": ^(id val) {
return [RCTConvert UITextAutocapitalizationType:val];
},
@"eyboardType": ^(id val) {
return [RCTConvert UIKeyboardType:val];
},
@"extAlignment": ^(id val) {
return [RCTConvert NSTextAlignment:val];
},
@"ritingDirection": ^(id val) {
return [RCTConvert NSWritingDirection:val];
},
@"Cap": ^(id val) {
return [RCTConvert CGLineCap:val];
},
@"Join": ^(id val) {
return [RCTConvert CGLineJoin:val];
},
@"ointerEvents": ^(id val) {
return [RCTConvert RCTPointerEvents:val];
},
};
});
for (NSString *subkey in converters) {
if ([key hasSuffix:subkey]) {
NSInteger (^converter)(NSString *) = converters[subkey];
json = @(converter(json));
break;
}
}
}
return RCTConvertValueWithEncoding(json, encoding);
}
id RCTConvertValue(id target, NSString *key, id json)
{
NSString *encoding = RCTPropertyEncoding(target, key, json);
return RCTConvertValueWithExplicitEncoding(target, key, json, encoding);
}
BOOL RCTSetProperty(id target, NSString *keypath, id value)
BOOL RCTSetProperty(id target, NSString *keyPath, SEL type, id json)
{
// Split keypath
NSArray *parts = [keypath componentsSeparatedByString:@"."];
NSArray *parts = [keyPath componentsSeparatedByString:@"."];
NSString *key = [parts lastObject];
for (NSUInteger i = 0; i < parts.count - 1; i++) {
target = [target valueForKey:parts[i]];
@ -879,48 +692,41 @@ BOOL RCTSetProperty(id target, NSString *keypath, id value)
}
}
// Get encoding
NSString *encoding = RCTPropertyEncoding(target, key, value);
if (!encoding) {
// Get property setter
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",
[[key substringToIndex:1] uppercaseString],
[key substringFromIndex:1]]);
// Fail early
if (![target respondsToSelector:setter]) {
return NO;
}
// Convert value
value = RCTConvertValueWithExplicitEncoding(target, keypath, value, encoding);
// Another nasty special case
if ([target isKindOfClass:[UITextField class]]) {
static NSDictionary *specialCases = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
specialCases = @{
@"autocapitalizationType": ^(UITextField *f, NSInteger v){ f.autocapitalizationType = v; },
@"autocorrectionType": ^(UITextField *f, NSInteger v){ f.autocorrectionType = v; },
@"spellCheckingType": ^(UITextField *f, NSInteger v){ f.spellCheckingType = v; },
@"keyboardType": ^(UITextField *f, NSInteger v){ f.keyboardType = v; },
@"keyboardAppearance": ^(UITextField *f, NSInteger v){ f.keyboardAppearance = v; },
@"returnKeyType": ^(UITextField *f, NSInteger v){ f.returnKeyType = v; },
@"enablesReturnKeyAutomatically": ^(UITextField *f, NSInteger v){ f.enablesReturnKeyAutomatically = !!v; },
@"secureTextEntry": ^(UITextField *f, NSInteger v){ f.secureTextEntry = !!v; }};
});
void (^block)(UITextField *f, NSInteger v) = specialCases[key];
if (block) {
block(target, [value integerValue]);
return YES;
}
}
// Get converted value
NSMethodSignature *signature = [RCTConvert methodSignatureForSelector:type];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setArgument:&type atIndex:1];
[invocation setArgument:&json atIndex:2];
[invocation invokeWithTarget:[RCTConvert class]];
NSUInteger length = [signature methodReturnLength];
void *value = malloc(length);
[invocation getReturnValue:value];
// Set converted value
[target setValue:value forKey:key];
signature = [target methodSignatureForSelector:setter];
invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setArgument:&setter atIndex:1];
[invocation setArgument:value atIndex:2];
[invocation invokeWithTarget:target];
free(value);
return YES;
}
BOOL RCTCopyProperty(id target, id source, NSString *keypath)
BOOL RCTCopyProperty(id target, id source, NSString *keyPath)
{
// Split keypath
NSArray *parts = [keypath componentsSeparatedByString:@"."];
NSArray *parts = [keyPath componentsSeparatedByString:@"."];
NSString *key = [parts lastObject];
for (NSUInteger i = 0; i < parts.count - 1; i++) {
source = [source valueForKey:parts[i]];
@ -930,19 +736,35 @@ BOOL RCTCopyProperty(id target, id source, NSString *keypath)
}
}
// Check class for property definition
if (!class_getProperty([source class], [key UTF8String])) {
// Check if setter exists
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",
[[key substringToIndex:1] uppercaseString],
[key substringFromIndex:1]]);
// Get property getter
SEL getter = NSSelectorFromString(key);
if (![source respondsToSelector:setter]
|| ![target respondsToSelector:setter]) {
return NO;
}
// Get property setter
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",
[[key substringToIndex:1] uppercaseString],
[key substringFromIndex:1]]);
// Fail early
if (![source respondsToSelector:getter] || ![target respondsToSelector:setter]) {
return NO;
}
[target setValue:[source valueForKey:key] forKey:key];
// Get converted value
NSMethodSignature *signature = [source methodSignatureForSelector:getter];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setArgument:&getter atIndex:1];
[invocation invokeWithTarget:source];
NSUInteger length = [signature methodReturnLength];
void *value = malloc(length);
[invocation getReturnValue:value];
// Set converted value
signature = [target methodSignatureForSelector:setter];
invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setArgument:&setter atIndex:1];
[invocation setArgument:value atIndex:2];
[invocation invokeWithTarget:target];
free(value);
return YES;
}

View File

@ -683,10 +683,8 @@ static void RCTSetViewProps(NSDictionary *props, UIView *view,
[props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set_%@:forView:withDefaultView:", key]);
// For regular views we don't attempt to set properties
// unless the view property has been explicitly exported.
RCTCallPropertySetter(setter, obj, view, defaultView, manager);
}];
}
@ -696,20 +694,8 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView
[props enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set_%@:forShadowView:withDefaultView:", key]);
RCTCallPropertySetter(setter, obj, shadowView, defaultView, manager);
// For shadow views we call any custom setter methods by default,
// but if none is specified, we attempt to set property anyway.
if (!RCTCallPropertySetter(setter, obj, shadowView, defaultView, manager)) {
if (obj == [NSNull null]) {
// Copy property from default view to current
// Note: not just doing `[defaultView valueForKey:key]`, the
// key may not exist, in which case we'd get an exception.
RCTCopyProperty(shadowView, defaultView, key);
} else {
RCTSetProperty(shadowView, key, obj);
}
}
}];
// Update layout

View File

@ -14,6 +14,17 @@
#import "RCTEventDispatcher.h"
#import "UIView+ReactKit.h"
@implementation RCTConvert(UIDatePicker)
RCT_ENUM_CONVERTER(UIDatePickerMode, (@{
@"time": @(UIDatePickerModeTime),
@"date": @(UIDatePickerModeDate),
@"datetime": @(UIDatePickerModeDateAndTime),
//@"countdown": @(UIDatePickerModeCountDownTimer) // not supported yet
}), UIDatePickerModeTime, integerValue)
@end
@implementation RCTDatePickerManager
- (UIView *)view
@ -25,12 +36,12 @@
return picker;
}
RCT_EXPORT_VIEW_PROPERTY(date)
RCT_EXPORT_VIEW_PROPERTY(minimumDate)
RCT_EXPORT_VIEW_PROPERTY(maximumDate)
RCT_EXPORT_VIEW_PROPERTY(minuteInterval)
RCT_REMAP_VIEW_PROPERTY(mode, datePickerMode)
RCT_REMAP_VIEW_PROPERTY(timeZoneOffsetInMinutes, timeZone)
RCT_EXPORT_VIEW_PROPERTY(date, NSDate)
RCT_EXPORT_VIEW_PROPERTY(minimumDate, NSDate)
RCT_EXPORT_VIEW_PROPERTY(maximumDate, NSDate)
RCT_EXPORT_VIEW_PROPERTY(minuteInterval, NSInteger)
RCT_REMAP_VIEW_PROPERTY(mode, datePickerMode, UIDatePickerMode)
RCT_REMAP_VIEW_PROPERTY(timeZoneOffsetInMinutes, timeZone, NSTimeZone)
- (void)onChange:(UIDatePicker *)sender
{

View File

@ -19,13 +19,9 @@ extern const CGFloat RCTMapZoomBoundBuffer;
@interface RCTMap: MKMapView
@property (nonatomic, assign) BOOL followUserLocation;
@property (nonatomic, copy) NSDictionary *JSONRegion;
@property (nonatomic, assign) CGFloat minDelta;
@property (nonatomic, assign) CGFloat maxDelta;
@property (nonatomic, assign) UIEdgeInsets legalLabelInsets;
@property (nonatomic, strong) NSTimer *regionChangeObserveTimer;
@end
#define FLUSH_NAN(value) \
(isnan(value) ? 0 : value)

View File

@ -18,19 +18,15 @@ const CLLocationDegrees RCTMapDefaultSpan = 0.005;
const NSTimeInterval RCTMapRegionChangeObserveInterval = 0.1;
const CGFloat RCTMapZoomBoundBuffer = 0.01;
@interface RCTMap()
@property (nonatomic, strong) UIView *legalLabel;
@property (nonatomic, strong) CLLocationManager *locationManager;
@end
@implementation RCTMap
{
UIView *_legalLabel;
CLLocationManager *_locationManager;
}
- (instancetype)init
{
self = [super init];
if (self) {
if ((self = [super init])) {
// Find Apple link label
for (UIView *subview in self.subviews) {
if ([NSStringFromClass(subview.class) isEqualToString:@"MKAttributionLabel"]) {
@ -45,7 +41,7 @@ const CGFloat RCTMapZoomBoundBuffer = 0.01;
- (void)dealloc
{
[self.regionChangeObserveTimer invalidate];
[_regionChangeObserveTimer invalidate];
}
- (void)layoutSubviews
@ -94,36 +90,23 @@ const CGFloat RCTMapZoomBoundBuffer = 0.01;
}
}
- (void)setJSONRegion:(NSDictionary *)region
- (void)setRegion:(MKCoordinateRegion)region
{
if (region) {
MKCoordinateRegion coordinateRegion = self.region;
coordinateRegion.center.latitude = [RCTConvert double:region[@"latitude"]];
coordinateRegion.center.longitude = [RCTConvert double:region[@"longitude"]];
if ([region[@"latitudeDelta"] isKindOfClass:[NSNumber class]]) {
coordinateRegion.span.latitudeDelta = [region[@"latitudeDelta"] doubleValue];
}
if ([region[@"longitudeDelta"] isKindOfClass:[NSNumber class]]) {
coordinateRegion.span.longitudeDelta = [region[@"longitudeDelta"] doubleValue];
}
[self setRegion:coordinateRegion animated:YES];
}
}
- (NSDictionary *)JSONRegion
{
MKCoordinateRegion region = self.region;
// If location is invalid, abort
if (!CLLocationCoordinate2DIsValid(region.center)) {
return nil;
return;
}
return @{
@"latitude": @(FLUSH_NAN(region.center.latitude)),
@"longitude": @(FLUSH_NAN(region.center.longitude)),
@"latitudeDelta": @(FLUSH_NAN(region.span.latitudeDelta)),
@"longitudeDelta": @(FLUSH_NAN(region.span.longitudeDelta)),
};
// If new span values are nil, use old values instead
if (!region.span.latitudeDelta) {
region.span.latitudeDelta = self.region.span.latitudeDelta;
}
if (!region.span.longitudeDelta) {
region.span.longitudeDelta = self.region.span.longitudeDelta;
}
// Animate to new position
[super setRegion:region animated:YES];
}
@end

View File

@ -14,6 +14,40 @@
#import "RCTMap.h"
#import "UIView+ReactKit.h"
@implementation RCTConvert(CoreLocation)
+ (CLLocationCoordinate2D)CLLocationCoordinate2D:(id)json
{
json = [self NSDictionary:json];
return (CLLocationCoordinate2D){
[self double:json[@"latitude"]],
[self double:json[@"longitude"]]
};
}
@end
@implementation RCTConvert(MapKit)
+ (MKCoordinateSpan)MKCoordinateSpan:(id)json
{
json = [self NSDictionary:json];
return (MKCoordinateSpan){
[self double:json[@"latitudeDelta"]],
[self double:json[@"longitudeDelta"]]
};
}
+ (MKCoordinateRegion)MKCoordinateRegion:(id)json
{
return (MKCoordinateRegion){
[self CLLocationCoordinate2D:json],
[self MKCoordinateSpan:json]
};
}
@end
@interface RCTMapManager() <MKMapViewDelegate>
@end
@ -27,15 +61,15 @@
return map;
}
RCT_EXPORT_VIEW_PROPERTY(showsUserLocation);
RCT_EXPORT_VIEW_PROPERTY(zoomEnabled);
RCT_EXPORT_VIEW_PROPERTY(rotateEnabled);
RCT_EXPORT_VIEW_PROPERTY(pitchEnabled);
RCT_EXPORT_VIEW_PROPERTY(scrollEnabled);
RCT_EXPORT_VIEW_PROPERTY(maxDelta);
RCT_EXPORT_VIEW_PROPERTY(minDelta);
RCT_EXPORT_VIEW_PROPERTY(legalLabelInsets);
RCT_REMAP_VIEW_PROPERTY(region, JSONRegion)
RCT_EXPORT_VIEW_PROPERTY(showsUserLocation, BOOL)
RCT_EXPORT_VIEW_PROPERTY(zoomEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(rotateEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(scrollEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(maxDelta, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(minDelta, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(legalLabelInsets, UIEdgeInsets)
RCT_EXPORT_VIEW_PROPERTY(region, MKCoordinateRegion)
#pragma mark MKMapViewDelegate
@ -112,15 +146,24 @@ RCT_REMAP_VIEW_PROPERTY(region, JSONRegion)
- (void)_emitRegionChangeEvent:(RCTMap *)mapView continuous:(BOOL)continuous
{
NSDictionary *region = mapView.JSONRegion;
if (region) {
NSDictionary *event = @{
@"target": [mapView reactTag],
@"continuous": @(continuous),
@"region": mapView.JSONRegion,
};
[self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
MKCoordinateRegion region = mapView.region;
if (!CLLocationCoordinate2DIsValid(region.center)) {
return;
}
#define FLUSH_NAN(value) (isnan(value) ? 0 : value)
NSDictionary *event = @{
@"target": [mapView reactTag],
@"continuous": @(continuous),
@"region": @{
@"latitude": @(FLUSH_NAN(region.center.latitude)),
@"longitude": @(FLUSH_NAN(region.center.longitude)),
@"latitudeDelta": @(FLUSH_NAN(region.span.latitudeDelta)),
@"longitudeDelta": @(FLUSH_NAN(region.span.longitudeDelta)),
}
};
[self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
}
@end

View File

@ -19,12 +19,11 @@
return [[RCTNavItem alloc] init];
}
RCT_EXPORT_VIEW_PROPERTY(title)
RCT_EXPORT_VIEW_PROPERTY(rightButtonTitle);
RCT_EXPORT_VIEW_PROPERTY(backButtonTitle);
RCT_EXPORT_VIEW_PROPERTY(tintColor);
RCT_EXPORT_VIEW_PROPERTY(barTintColor);
RCT_EXPORT_VIEW_PROPERTY(titleTextColor);
RCT_EXPORT_VIEW_PROPERTY(title, NSString)
RCT_EXPORT_VIEW_PROPERTY(rightButtonTitle, NSString);
RCT_EXPORT_VIEW_PROPERTY(backButtonTitle, NSString);
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor);
RCT_EXPORT_VIEW_PROPERTY(barTintColor, UIColor);
RCT_EXPORT_VIEW_PROPERTY(titleTextColor, UIColor);
@end

View File

@ -22,7 +22,7 @@
return [[RCTNavigator alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
}
RCT_EXPORT_VIEW_PROPERTY(requestedTopOfStack)
RCT_EXPORT_VIEW_PROPERTY(requestedTopOfStack, NSInteger)
- (NSDictionary *)customDirectEventTypes
{

View File

@ -17,14 +17,15 @@
const NSInteger UNINITIALIZED_INDEX = -1;
@interface RCTPicker() <UIPickerViewDataSource, UIPickerViewDelegate>
@end
@implementation RCTPicker
{
RCTEventDispatcher *_eventDispatcher;
NSArray *_items;
NSInteger _selectedIndex;
}
@end
@implementation RCTPicker
- (id)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
{
@ -64,14 +65,14 @@ const NSInteger UNINITIALIZED_INDEX = -1;
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [_items count];
return _items.count;
}
#pragma mark - UIPickerViewDelegate methods
- (NSDictionary *)itemForRow:(NSInteger)row
{
return (NSDictionary*)[_items objectAtIndex:row];
return _items[row];
}
- (id)valueForRow:(NSInteger)row

View File

@ -20,8 +20,8 @@
return [[RCTPicker alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
}
RCT_EXPORT_VIEW_PROPERTY(items)
RCT_EXPORT_VIEW_PROPERTY(selectedIndex)
RCT_EXPORT_VIEW_PROPERTY(items, NSDictionaryArray)
RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger)
- (NSDictionary *)constantsToExport
{

View File

@ -22,29 +22,29 @@
return [[RCTScrollView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
}
RCT_EXPORT_VIEW_PROPERTY(alwaysBounceHorizontal)
RCT_EXPORT_VIEW_PROPERTY(alwaysBounceVertical)
RCT_EXPORT_VIEW_PROPERTY(bounces)
RCT_EXPORT_VIEW_PROPERTY(bouncesZoom)
RCT_EXPORT_VIEW_PROPERTY(canCancelContentTouches)
RCT_EXPORT_VIEW_PROPERTY(centerContent)
RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets)
RCT_EXPORT_VIEW_PROPERTY(decelerationRate)
RCT_EXPORT_VIEW_PROPERTY(directionalLockEnabled)
RCT_EXPORT_VIEW_PROPERTY(keyboardDismissMode)
RCT_EXPORT_VIEW_PROPERTY(maximumZoomScale)
RCT_EXPORT_VIEW_PROPERTY(minimumZoomScale)
RCT_EXPORT_VIEW_PROPERTY(pagingEnabled)
RCT_EXPORT_VIEW_PROPERTY(scrollEnabled)
RCT_EXPORT_VIEW_PROPERTY(scrollsToTop)
RCT_EXPORT_VIEW_PROPERTY(showsHorizontalScrollIndicator)
RCT_EXPORT_VIEW_PROPERTY(showsVerticalScrollIndicator)
RCT_EXPORT_VIEW_PROPERTY(stickyHeaderIndices);
RCT_EXPORT_VIEW_PROPERTY(throttleScrollCallbackMS);
RCT_EXPORT_VIEW_PROPERTY(zoomScale);
RCT_EXPORT_VIEW_PROPERTY(contentInset);
RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets);
RCT_REMAP_VIEW_PROPERTY(contentOffset, scrollView.contentOffset);
RCT_EXPORT_VIEW_PROPERTY(alwaysBounceHorizontal, BOOL)
RCT_EXPORT_VIEW_PROPERTY(alwaysBounceVertical, BOOL)
RCT_EXPORT_VIEW_PROPERTY(bounces, BOOL)
RCT_EXPORT_VIEW_PROPERTY(bouncesZoom, BOOL)
RCT_EXPORT_VIEW_PROPERTY(canCancelContentTouches, BOOL)
RCT_EXPORT_VIEW_PROPERTY(centerContent, BOOL)
RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)
RCT_EXPORT_VIEW_PROPERTY(decelerationRate, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(directionalLockEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(keyboardDismissMode, UIScrollViewKeyboardDismissMode)
RCT_EXPORT_VIEW_PROPERTY(maximumZoomScale, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(minimumZoomScale, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(pagingEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(scrollEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(scrollsToTop, BOOL)
RCT_EXPORT_VIEW_PROPERTY(showsHorizontalScrollIndicator, BOOL)
RCT_EXPORT_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL)
RCT_EXPORT_VIEW_PROPERTY(stickyHeaderIndices, NSNumberArray);
RCT_EXPORT_VIEW_PROPERTY(throttleScrollCallbackMS, double);
RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat);
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets);
RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets);
RCT_REMAP_VIEW_PROPERTY(contentOffset, scrollView.contentOffset, CGPoint);
- (NSDictionary *)constantsToExport
{

View File

@ -68,10 +68,10 @@ typedef void (^RCTApplierBlock)(RCTSparseArray *);
/**
* Border. Defaults to { 0, 0, 0, 0 }.
*/
@property (nonatomic, assign) CGFloat borderTop;
@property (nonatomic, assign) CGFloat borderLeft;
@property (nonatomic, assign) CGFloat borderBottom;
@property (nonatomic, assign) CGFloat borderRight;
@property (nonatomic, assign) CGFloat borderTopWidth;
@property (nonatomic, assign) CGFloat borderLeftWidth;
@property (nonatomic, assign) CGFloat borderBottomWidth;
@property (nonatomic, assign) CGFloat borderRightWidth;
- (void)setBorderWidth:(CGFloat)value;

View File

@ -411,12 +411,12 @@ RCT_PADDING_PROPERTY(Right, RIGHT)
// Border
#define RCT_BORDER_PROPERTY(prop, metaProp) \
- (void)setBorder##prop:(CGFloat)value \
- (void)setBorder##prop##Width:(CGFloat)value \
{ \
_cssNode->style.border[CSS_##metaProp] = value; \
[self dirtyLayout]; \
} \
- (CGFloat)border##prop \
- (CGFloat)border##prop##Width \
{ \
return _cssNode->style.border[META_PROP_##metaProp]; \
}

View File

@ -45,6 +45,8 @@
[self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
}
RCT_EXPORT_VIEW_PROPERTY(value);
RCT_EXPORT_VIEW_PROPERTY(value, float);
RCT_EXPORT_VIEW_PROPERTY(minimumValue, float);
RCT_EXPORT_VIEW_PROPERTY(maximumValue, float);
@end

View File

@ -37,10 +37,10 @@
}
}
RCT_EXPORT_VIEW_PROPERTY(onTintColor);
RCT_EXPORT_VIEW_PROPERTY(tintColor);
RCT_EXPORT_VIEW_PROPERTY(thumbTintColor);
RCT_EXPORT_VIEW_PROPERTY(on);
RCT_EXPORT_VIEW_PROPERTY(enabled);
RCT_EXPORT_VIEW_PROPERTY(onTintColor, UIColor);
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor);
RCT_EXPORT_VIEW_PROPERTY(thumbTintColor, UIColor);
RCT_EXPORT_VIEW_PROPERTY(on, BOOL);
RCT_EXPORT_VIEW_PROPERTY(enabled, BOOL);
@end

View File

@ -19,11 +19,11 @@
return [[RCTTabBarItem alloc] init];
}
RCT_EXPORT_VIEW_PROPERTY(selected);
RCT_EXPORT_VIEW_PROPERTY(icon);
RCT_REMAP_VIEW_PROPERTY(selectedIcon, barItem.selectedImage);
RCT_REMAP_VIEW_PROPERTY(badgeValue, barItem.badgeValue);
RCT_CUSTOM_VIEW_PROPERTY(title, RCTTabBarItem)
RCT_EXPORT_VIEW_PROPERTY(selected, BOOL);
RCT_EXPORT_VIEW_PROPERTY(icon, NSString);
RCT_REMAP_VIEW_PROPERTY(selectedIcon, barItem.selectedImage, NSString);
RCT_REMAP_VIEW_PROPERTY(badgeValue, barItem.badgeValue, NSString);
RCT_CUSTOM_VIEW_PROPERTY(title, NSString, RCTTabBarItem)
{
view.barItem.title = json ? [RCTConvert NSString:json] : defaultView.barItem.title;
view.barItem.imageInsets = [view.barItem.title length] ? UIEdgeInsetsZero : (UIEdgeInsets){6, 0, -6, 0};

View File

@ -22,32 +22,28 @@
return [[RCTTextField alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
}
RCT_EXPORT_VIEW_PROPERTY(caretHidden)
RCT_EXPORT_VIEW_PROPERTY(autoCorrect)
RCT_EXPORT_VIEW_PROPERTY(enabled)
RCT_EXPORT_VIEW_PROPERTY(placeholder)
RCT_EXPORT_VIEW_PROPERTY(text)
RCT_EXPORT_VIEW_PROPERTY(clearButtonMode)
RCT_EXPORT_VIEW_PROPERTY(keyboardType)
RCT_REMAP_VIEW_PROPERTY(color, textColor)
RCT_CUSTOM_VIEW_PROPERTY(autoCapitalize, RCTTextField)
{
view.autocapitalizationType = json ? [RCTConvert UITextAutocapitalizationType:json]
: defaultView.autocapitalizationType;
}
RCT_CUSTOM_VIEW_PROPERTY(fontSize, RCTTextField)
RCT_EXPORT_VIEW_PROPERTY(caretHidden, BOOL)
RCT_EXPORT_VIEW_PROPERTY(autoCorrect, BOOL)
RCT_EXPORT_VIEW_PROPERTY(enabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(placeholder, NSString)
RCT_EXPORT_VIEW_PROPERTY(text, NSString)
RCT_EXPORT_VIEW_PROPERTY(clearButtonMode, UITextFieldViewMode)
RCT_EXPORT_VIEW_PROPERTY(keyboardType, UIKeyboardType)
RCT_REMAP_VIEW_PROPERTY(color, textColor, UIColor)
RCT_REMAP_VIEW_PROPERTY(autoCapitalize, autocapitalizationType, UITextAutocapitalizationType)
RCT_CUSTOM_VIEW_PROPERTY(fontSize, CGFloat, RCTTextField)
{
view.font = [RCTConvert UIFont:view.font withSize:json ?: @(defaultView.font.pointSize)];
}
RCT_CUSTOM_VIEW_PROPERTY(fontWeight, RCTTextField)
RCT_CUSTOM_VIEW_PROPERTY(fontWeight, NSString, RCTTextField)
{
view.font = [RCTConvert UIFont:view.font withWeight:json]; // defaults to normal
}
RCT_CUSTOM_VIEW_PROPERTY(fontStyle, RCTTextField)
RCT_CUSTOM_VIEW_PROPERTY(fontStyle, NSString, RCTTextField)
{
view.font = [RCTConvert UIFont:view.font withStyle:json]; // defaults to normal
}
RCT_CUSTOM_VIEW_PROPERTY(fontFamily, RCTTextField)
RCT_CUSTOM_VIEW_PROPERTY(fontFamily, NSString, RCTTextField)
{
view.font = [RCTConvert UIFont:view.font withFamily:json ?: defaultView.font.familyName];
}

View File

@ -11,6 +11,17 @@
#import "RCTConvert.h"
@implementation RCTConvert (UIActivityIndicatorView)
RCT_ENUM_CONVERTER(UIActivityIndicatorViewStyle, (@{
@"white-large": @(UIActivityIndicatorViewStyleWhiteLarge),
@"large-white": @(UIActivityIndicatorViewStyleWhiteLarge),
@"white": @(UIActivityIndicatorViewStyleWhite),
@"gray": @(UIActivityIndicatorViewStyleGray),
}), UIActivityIndicatorViewStyleWhiteLarge, integerValue)
@end
@implementation RCTUIActivityIndicatorViewManager
- (UIView *)view
@ -18,9 +29,9 @@
return [[UIActivityIndicatorView alloc] init];
}
RCT_EXPORT_VIEW_PROPERTY(activityIndicatorViewStyle)
RCT_EXPORT_VIEW_PROPERTY(color)
RCT_CUSTOM_VIEW_PROPERTY(animating, UIActivityIndicatorView)
RCT_EXPORT_VIEW_PROPERTY(activityIndicatorViewStyle, UIActivityIndicatorViewStyle)
RCT_EXPORT_VIEW_PROPERTY(color, UIColor)
RCT_CUSTOM_VIEW_PROPERTY(animating, BOOL, UIActivityIndicatorView)
{
BOOL animating = json ? [json boolValue] : [defaultView isAnimating];
if (animating != [view isAnimating]) {

View File

@ -106,20 +106,28 @@ typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, RCTSparseArray *v
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(RCTSparseArray *)shadowViewRegistry;
/**
* This handles the simple case, where JS and native property names match
* And the type can be automatically inferred.
* This handles the simple case, where JS and native property names match.
*/
#define RCT_EXPORT_VIEW_PROPERTY(name) \
RCT_REMAP_VIEW_PROPERTY(name, name)
#define RCT_EXPORT_VIEW_PROPERTY(name, type) RCT_REMAP_VIEW_PROPERTY(name, name, type)
#define RCT_EXPORT_SHADOW_PROPERTY(name, type) RCT_REMAP_SHADOW_PROPERTY(name, name, type)
/**
* This macro maps a named property on the module to an arbitrary key path
* within the view.
* within the view or shadowView.
*/
#define RCT_REMAP_VIEW_PROPERTY(name, keypath) \
#define RCT_REMAP_VIEW_PROPERTY(name, keyPath, type) \
- (void)set_##name:(id)json forView:(id)view withDefaultView:(id)defaultView { \
if ((json && !RCTSetProperty(view, @#keypath, json)) || \
(!json && !RCTCopyProperty(view, defaultView, @#keypath))) { \
if ((json && !RCTSetProperty(view, @#keyPath, @selector(type:), json)) || \
(!json && !RCTCopyProperty(view, defaultView, @#keyPath))) { \
RCTLogError(@"%@ does not have setter for `%s` property", [view class], #name); \
} \
}
#define RCT_REMAP_SHADOW_PROPERTY(name, keyPath, type) \
- (void)set_##name:(id)json forShadowView:(id)view withDefaultView:(id)defaultView { \
if ((json && !RCTSetProperty(view, @#keyPath, @selector(type:), json)) || \
(!json && !RCTCopyProperty(view, defaultView, @#keyPath))) { \
RCTLogError(@"%@ does not have setter for `%s` property", [view class], #name); \
} \
}
@ -129,10 +137,10 @@ RCT_REMAP_VIEW_PROPERTY(name, name)
* view properties. The macro should be followed by a method body, which can
* refer to "json", "view" and "defaultView" to implement the required logic.
*/
#define RCT_CUSTOM_VIEW_PROPERTY(name, viewClass) \
#define RCT_CUSTOM_VIEW_PROPERTY(name, type, viewClass) \
- (void)set_##name:(id)json forView:(viewClass *)view withDefaultView:(viewClass *)defaultView
#define RCT_CUSTOM_SHADOW_PROPERTY(name, viewClass) \
#define RCT_CUSTOM_SHADOW_PROPERTY(name, type, viewClass) \
- (void)set_##name:(id)json forShadowView:(viewClass *)view withDefaultView:(viewClass *)defaultView
/**

View File

@ -71,25 +71,25 @@
#pragma mark - View properties
RCT_EXPORT_VIEW_PROPERTY(accessibilityLabel)
RCT_EXPORT_VIEW_PROPERTY(hidden)
RCT_EXPORT_VIEW_PROPERTY(backgroundColor)
RCT_REMAP_VIEW_PROPERTY(accessible, isAccessibilityElement)
RCT_REMAP_VIEW_PROPERTY(testID, accessibilityIdentifier)
RCT_REMAP_VIEW_PROPERTY(opacity, alpha)
RCT_REMAP_VIEW_PROPERTY(shadowColor, layer.shadowColor);
RCT_REMAP_VIEW_PROPERTY(shadowOffset, layer.shadowOffset);
RCT_REMAP_VIEW_PROPERTY(shadowOpacity, layer.shadowOpacity)
RCT_REMAP_VIEW_PROPERTY(shadowRadius, layer.shadowRadius)
RCT_REMAP_VIEW_PROPERTY(borderColor, layer.borderColor);
RCT_REMAP_VIEW_PROPERTY(borderRadius, layer.cornerRadius)
RCT_REMAP_VIEW_PROPERTY(borderWidth, layer.borderWidth)
RCT_REMAP_VIEW_PROPERTY(transformMatrix, layer.transform)
RCT_CUSTOM_VIEW_PROPERTY(overflow, UIView)
RCT_EXPORT_VIEW_PROPERTY(accessibilityLabel, NSString)
RCT_EXPORT_VIEW_PROPERTY(hidden, BOOL)
RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor)
RCT_REMAP_VIEW_PROPERTY(accessible, isAccessibilityElement, BOOL)
RCT_REMAP_VIEW_PROPERTY(testID, accessibilityIdentifier, NSString)
RCT_REMAP_VIEW_PROPERTY(opacity, alpha, CGFloat)
RCT_REMAP_VIEW_PROPERTY(shadowColor, layer.shadowColor, CGColor);
RCT_REMAP_VIEW_PROPERTY(shadowOffset, layer.shadowOffset, CGSize);
RCT_REMAP_VIEW_PROPERTY(shadowOpacity, layer.shadowOpacity, CGFloat)
RCT_REMAP_VIEW_PROPERTY(shadowRadius, layer.shadowRadius, CGFloat)
RCT_REMAP_VIEW_PROPERTY(borderColor, layer.borderColor, CGColor);
RCT_REMAP_VIEW_PROPERTY(borderRadius, layer.cornerRadius, CGFloat)
RCT_REMAP_VIEW_PROPERTY(borderWidth, layer.borderWidth, CGFloat)
RCT_REMAP_VIEW_PROPERTY(transformMatrix, layer.transform, CATransform3D)
RCT_CUSTOM_VIEW_PROPERTY(overflow, css_overflow, RCTView)
{
view.clipsToBounds = json ? ![RCTConvert css_overflow:json] : defaultView.clipsToBounds;
}
RCT_CUSTOM_VIEW_PROPERTY(pointerEvents, RCTView)
RCT_CUSTOM_VIEW_PROPERTY(pointerEvents, RCTPointerEvents, RCTView)
{
if ([view respondsToSelector:@selector(setPointerEvents:)]) {
view.pointerEvents = json ? [RCTConvert RCTPointerEvents:json] : defaultView.pointerEvents;
@ -116,7 +116,7 @@ RCT_CUSTOM_VIEW_PROPERTY(pointerEvents, RCTView)
RCTLogError(@"UIView base class does not support pointerEvent value: %@", json);
}
}
RCT_CUSTOM_VIEW_PROPERTY(removeClippedSubviews, RCTView)
RCT_CUSTOM_VIEW_PROPERTY(removeClippedSubviews, BOOL, RCTView)
{
if ([view respondsToSelector:@selector(setRemoveClippedSubviews:)]) {
view.removeClippedSubviews = json ? [RCTConvert BOOL:json] : defaultView.removeClippedSubviews;
@ -125,45 +125,59 @@ RCT_CUSTOM_VIEW_PROPERTY(removeClippedSubviews, RCTView)
#pragma mark - ShadowView properties
RCT_CUSTOM_SHADOW_PROPERTY(backgroundColor, RCTShadowView)
RCT_EXPORT_SHADOW_PROPERTY(top, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(right, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(bottom, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(left, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(width, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(height, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(borderTopWidth, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(borderRightWidth, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(borderBottomWidth, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(borderLeftWidth, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(borderWidth, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(marginTop, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(marginRight, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(marginBottom, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(marginLeft, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(marginVertical, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(marginHorizontal, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(margin, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(paddingTop, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(paddingRight, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(paddingBottom, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(paddingLeft, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(paddingVertical, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(paddingHorizontal, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(padding, CGFloat);
RCT_EXPORT_SHADOW_PROPERTY(flex, CGFloat)
RCT_EXPORT_SHADOW_PROPERTY(flexDirection, css_flex_direction_t)
RCT_EXPORT_SHADOW_PROPERTY(flexWrap, css_wrap_type_t)
RCT_EXPORT_SHADOW_PROPERTY(justifyContent, css_justify_t)
RCT_EXPORT_SHADOW_PROPERTY(alignItems, css_align_t)
RCT_EXPORT_SHADOW_PROPERTY(alignSelf, css_align_t)
RCT_REMAP_SHADOW_PROPERTY(position, positionType, css_position_type_t)
RCT_CUSTOM_SHADOW_PROPERTY(backgroundColor, UIColor, RCTShadowView)
{
view.backgroundColor = json ? [RCTConvert UIColor:json] : defaultView.backgroundColor;
view.isBGColorExplicitlySet = json ? YES : defaultView.isBGColorExplicitlySet;
}
RCT_CUSTOM_SHADOW_PROPERTY(flexDirection, RCTShadowView)
{
view.flexDirection = json? [RCTConvert css_flex_direction_t:json] : defaultView.flexDirection;
}
RCT_CUSTOM_SHADOW_PROPERTY(flexWrap, RCTShadowView)
{
view.flexWrap = json ? [RCTConvert css_wrap_type_t:json] : defaultView.flexWrap;
}
RCT_CUSTOM_SHADOW_PROPERTY(justifyContent, RCTShadowView)
{
view.justifyContent = json ? [RCTConvert css_justify_t:json] : defaultView.justifyContent;
}
RCT_CUSTOM_SHADOW_PROPERTY(alignItems, RCTShadowView)
{
view.alignItems = json ? [RCTConvert css_align_t:json] : defaultView.alignItems;
}
RCT_CUSTOM_SHADOW_PROPERTY(alignSelf, RCTShadowView)
{
view.alignSelf = json ? [RCTConvert css_align_t:json] : defaultView.alignSelf;
}
RCT_CUSTOM_SHADOW_PROPERTY(position, RCTShadowView)
{
view.positionType = json ? [RCTConvert css_position_type_t:json] : defaultView.positionType;
}
// Border properties - to be deprecated
RCT_REMAP_VIEW_PROPERTY(borderTopWidth, reactBorderTop.width);
RCT_REMAP_VIEW_PROPERTY(borderRightWidth, reactBorderRight.width);
RCT_REMAP_VIEW_PROPERTY(borderBottomWidth, reactBorderBottom.width);
RCT_REMAP_VIEW_PROPERTY(borderLeftWidth, reactBorderLeft.width);
RCT_REMAP_VIEW_PROPERTY(borderTopColor, reactBorderTop.color);
RCT_REMAP_VIEW_PROPERTY(borderRightColor, reactBorderRight.color);
RCT_REMAP_VIEW_PROPERTY(borderBottomColor, reactBorderBottom.color);
RCT_REMAP_VIEW_PROPERTY(borderLeftColor, reactBorderLeft.color);
RCT_REMAP_VIEW_PROPERTY(borderTopWidth, reactBorderTop.width, CGFloat);
RCT_REMAP_VIEW_PROPERTY(borderRightWidth, reactBorderRight.width, CGFloat);
RCT_REMAP_VIEW_PROPERTY(borderBottomWidth, reactBorderBottom.width, CGFloat);
RCT_REMAP_VIEW_PROPERTY(borderLeftWidth, reactBorderLeft.width, CGFloat);
RCT_REMAP_VIEW_PROPERTY(borderTopColor, reactBorderTop.color, UIColor);
RCT_REMAP_VIEW_PROPERTY(borderRightColor, reactBorderRight.color, UIColor);
RCT_REMAP_VIEW_PROPERTY(borderBottomColor, reactBorderBottom.color, UIColor);
RCT_REMAP_VIEW_PROPERTY(borderLeftColor, reactBorderLeft.color, UIColor);
@end

View File

@ -21,10 +21,10 @@
return [[RCTWebView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
}
RCT_REMAP_VIEW_PROPERTY(url, URL);
RCT_EXPORT_VIEW_PROPERTY(contentInset);
RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets);
RCT_EXPORT_VIEW_PROPERTY(shouldInjectAJAXHandler);
RCT_REMAP_VIEW_PROPERTY(url, URL, NSURL);
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets);
RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, UIEdgeInsets);
RCT_EXPORT_VIEW_PROPERTY(shouldInjectAJAXHandler, BOOL);
- (NSDictionary *)constantsToExport
{