diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 2ee75eb97..df27defa6 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -227,6 +227,11 @@ const TextInput = createReactClass({ * @platform android */ autoGrow: PropTypes.bool, + /** + * Specifies whether fonts should scale to respect Text Size accessibility settings. The + * default is `true`. + */ + allowFontScaling: PropTypes.bool, /** * If `false`, text is not editable. The default value is `true`. */ @@ -566,7 +571,11 @@ const TextInput = createReactClass({ */ caretHidden: PropTypes.bool, }, - + getDefaultProps(): Object { + return { + allowFontScaling: true, + }; + }, /** * `NativeMethodsMixin` will look for this when invoking `setNativeProps`. We * make `this` look like an actual native component class. @@ -704,7 +713,7 @@ const TextInput = createReactClass({ 'Cannot specify both value and children.' ); if (childCount >= 1) { - children = {children}; + children = {children}; } if (props.inputView) { children = [children, props.inputView]; diff --git a/Libraries/Text/RCTFontAttributes.h b/Libraries/Text/RCTFontAttributes.h new file mode 100644 index 000000000..37b9954cd --- /dev/null +++ b/Libraries/Text/RCTFontAttributes.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +#import "RCTFontAttributesDelegate.h" + +@class RCTAccessibilityManager; + +@interface RCTFontAttributes : NSObject + +@property (nonatomic, weak) id delegate; + +@property (readonly, nonatomic, strong) UIFont *font; + +@property (nonatomic, assign) BOOL allowFontScaling; +@property (nonatomic, copy) NSString *fontFamily; +@property (nonatomic, strong) NSNumber *fontSize; +@property (nonatomic, assign) CGFloat fontSizeMultiplier; +@property (nonatomic, copy) NSString *fontStyle; +@property (nonatomic, copy) NSString *fontWeight; + +- (instancetype)initWithAccessibilityManager:(RCTAccessibilityManager *)accessibilityManager; + +@end diff --git a/Libraries/Text/RCTFontAttributes.m b/Libraries/Text/RCTFontAttributes.m new file mode 100644 index 000000000..3cb8da119 --- /dev/null +++ b/Libraries/Text/RCTFontAttributes.m @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTFontAttributes.h" + +#import +#import +#import +#import + +@interface RCTFontAttributes () +{ + RCTAccessibilityManager *_accessibilityManager; +} + +@property (nonatomic, strong) UIFont *font; + +@end + +@implementation RCTFontAttributes + +- (instancetype)initWithAccessibilityManager:(RCTAccessibilityManager *)accessibilityManager +{ + RCTAssertParam(accessibilityManager); + + if (self = [super init]) { + _accessibilityManager = accessibilityManager; + _fontSizeMultiplier = _accessibilityManager.multiplier; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(contentSizeMultiplierDidChange) + name:RCTAccessibilityManagerDidUpdateMultiplierNotification + object:_accessibilityManager]; + + [self updateFont]; + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)contentSizeMultiplierDidChange +{ + self.fontSizeMultiplier = _accessibilityManager.multiplier; +} + +- (void)setAllowFontScaling:(BOOL)allowFontScaling +{ + _allowFontScaling = allowFontScaling; + [self updateFont]; +} + +- (void)setFontFamily:(NSString *)fontFamily +{ + _fontFamily = fontFamily; + [self updateFont]; +} + +- (void)setFontSize:(NSNumber *)fontSize +{ + _fontSize = fontSize; + [self updateFont]; +} + +- (void)setFontSizeMultiplier:(CGFloat)fontSizeMultiplier +{ + _fontSizeMultiplier = fontSizeMultiplier; + + if (_fontSizeMultiplier == 0) { + RCTLogError(@"fontSizeMultiplier value must be > zero."); + _fontSizeMultiplier = 1.0; + } + + [self updateFont]; +} + +- (void)setFontStyle:(NSString *)fontStyle +{ + _fontStyle = fontStyle; + [self updateFont]; +} + +- (void)setFontWeight:(NSString *)fontWeight +{ + _fontWeight = fontWeight; + [self updateFont]; +} + +- (void)updateFont +{ + CGFloat scaleMultiplier = self.allowFontScaling ? self.fontSizeMultiplier : 1.0; + self.font = [RCTFont updateFont:nil + withFamily:self.fontFamily + size:self.fontSize + weight:self.fontWeight + style:self.fontStyle + variant:nil + scaleMultiplier:scaleMultiplier]; + + [self.delegate fontAttributesDidChangeWithFont:self.font]; +} + +@end diff --git a/Libraries/Text/RCTFontAttributesDelegate.h b/Libraries/Text/RCTFontAttributesDelegate.h new file mode 100644 index 000000000..6436c3c8c --- /dev/null +++ b/Libraries/Text/RCTFontAttributesDelegate.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +@protocol RCTFontAttributesDelegate + +- (void)fontAttributesDidChangeWithFont:(UIFont *)font; + +@end diff --git a/Libraries/Text/RCTText.xcodeproj/project.pbxproj b/Libraries/Text/RCTText.xcodeproj/project.pbxproj index 9beaaaa51..4b8d30f39 100644 --- a/Libraries/Text/RCTText.xcodeproj/project.pbxproj +++ b/Libraries/Text/RCTText.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ 59F60E921E661BDD0081153B /* RCTShadowTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 59F60E8E1E661BDD0081153B /* RCTShadowTextField.m */; }; 59F60E931E661BDD0081153B /* RCTShadowTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59F60E901E661BDD0081153B /* RCTShadowTextView.m */; }; 59F60E941E661BDD0081153B /* RCTShadowTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59F60E901E661BDD0081153B /* RCTShadowTextView.m */; }; + A85C829A1F742AA20036C019 /* RCTFontAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = A85C82991F742AA20036C019 /* RCTFontAttributes.m */; }; AF3225F91DE5574F00D3E7E7 /* RCTConvert+Text.m in Sources */ = {isa = PBXBuildFile; fileRef = AF3225F81DE5574F00D3E7E7 /* RCTConvert+Text.m */; }; AF3225FA1DE5574F00D3E7E7 /* RCTConvert+Text.m in Sources */ = {isa = PBXBuildFile; fileRef = AF3225F81DE5574F00D3E7E7 /* RCTConvert+Text.m */; }; /* End PBXBuildFile section */ @@ -111,6 +112,9 @@ 59F60E8E1E661BDD0081153B /* RCTShadowTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTShadowTextField.m; sourceTree = ""; }; 59F60E8F1E661BDD0081153B /* RCTShadowTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTShadowTextView.h; sourceTree = ""; }; 59F60E901E661BDD0081153B /* RCTShadowTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTShadowTextView.m; sourceTree = ""; }; + A85C82981F742AA20036C019 /* RCTFontAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFontAttributes.h; sourceTree = ""; }; + A85C82991F742AA20036C019 /* RCTFontAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTFontAttributes.m; sourceTree = ""; }; + A85C82BA1F742D8F0036C019 /* RCTFontAttributesDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFontAttributesDelegate.h; sourceTree = ""; }; AF3225F71DE5574F00D3E7E7 /* RCTConvert+Text.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+Text.h"; sourceTree = ""; }; AF3225F81DE5574F00D3E7E7 /* RCTConvert+Text.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+Text.m"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -126,6 +130,9 @@ 599DF25D1F0304B30079B53E /* RCTBackedTextInputViewProtocol.h */, AF3225F71DE5574F00D3E7E7 /* RCTConvert+Text.h */, AF3225F81DE5574F00D3E7E7 /* RCTConvert+Text.m */, + A85C82981F742AA20036C019 /* RCTFontAttributes.h */, + A85C82991F742AA20036C019 /* RCTFontAttributes.m */, + A85C82BA1F742D8F0036C019 /* RCTFontAttributesDelegate.h */, 58B511C61A9E6C5C00147676 /* RCTRawTextManager.h */, 58B511C71A9E6C5C00147676 /* RCTRawTextManager.m */, 58B511C81A9E6C5C00147676 /* RCTShadowRawText.h */, @@ -278,6 +285,7 @@ 1362F1001B4D51F400E06D8C /* RCTTextField.m in Sources */, 59AF89AA1EDCBCC700F004B1 /* RCTUITextField.m in Sources */, 598F41261F145D4900B8495B /* RCTBackedTextInputDelegateAdapter.m in Sources */, + A85C829A1F742AA20036C019 /* RCTFontAttributes.m in Sources */, 58B512161A9E6EFF00147676 /* RCTText.m in Sources */, 599DF2641F03076D0079B53E /* RCTTextInput.m in Sources */, 1362F1011B4D51F400E06D8C /* RCTTextFieldManager.m in Sources */, diff --git a/Libraries/Text/RCTTextField.m b/Libraries/Text/RCTTextField.m index 567ab31a9..e6addcaf1 100644 --- a/Libraries/Text/RCTTextField.m +++ b/Libraries/Text/RCTTextField.m @@ -12,6 +12,7 @@ #import #import #import +#import #import #import #import @@ -40,6 +41,7 @@ _backedTextInput = [[RCTUITextField alloc] initWithFrame:self.bounds]; _backedTextInput.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _backedTextInput.textInputDelegate = self; + _backedTextInput.font = self.fontAttributes.font; [self addSubview:_backedTextInput]; } diff --git a/Libraries/Text/RCTTextFieldManager.m b/Libraries/Text/RCTTextFieldManager.m index f43e60765..7e0d1dc24 100644 --- a/Libraries/Text/RCTTextFieldManager.m +++ b/Libraries/Text/RCTTextFieldManager.m @@ -35,11 +35,16 @@ RCT_EXPORT_MODULE() #pragma mark - Unified properties +RCT_REMAP_VIEW_PROPERTY(allowFontScaling, fontAttributes.allowFontScaling, BOOL) RCT_REMAP_VIEW_PROPERTY(autoCapitalize, backedTextInputView.autocapitalizationType, UITextAutocapitalizationType) RCT_REMAP_VIEW_PROPERTY(autoCorrect, backedTextInputView.autocorrectionType, UITextAutocorrectionType) RCT_REMAP_VIEW_PROPERTY(color, backedTextInputView.textColor, UIColor) RCT_REMAP_VIEW_PROPERTY(editable, backedTextInputView.editable, BOOL) RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, backedTextInputView.enablesReturnKeyAutomatically, BOOL) +RCT_REMAP_VIEW_PROPERTY(fontSize, fontAttributes.fontSize, NSNumber) +RCT_REMAP_VIEW_PROPERTY(fontWeight, fontAttributes.fontWeight, NSString) +RCT_REMAP_VIEW_PROPERTY(fontStyle, fontAttributes.fontStyle, NSString) +RCT_REMAP_VIEW_PROPERTY(fontFamily, fontAttributes.fontFamily, NSString) RCT_REMAP_VIEW_PROPERTY(keyboardAppearance, backedTextInputView.keyboardAppearance, UIKeyboardAppearance) RCT_REMAP_VIEW_PROPERTY(keyboardType, backedTextInputView.keyboardType, UIKeyboardType) RCT_REMAP_VIEW_PROPERTY(placeholder, backedTextInputView.placeholder, NSString) @@ -61,22 +66,7 @@ RCT_EXPORT_VIEW_PROPERTY(text, NSString) RCT_REMAP_VIEW_PROPERTY(caretHidden, backedTextInputView.caretHidden, BOOL) RCT_REMAP_VIEW_PROPERTY(clearButtonMode, backedTextInputView.clearButtonMode, UITextFieldViewMode) RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock) -RCT_CUSTOM_VIEW_PROPERTY(fontSize, NSNumber, RCTTextField) -{ - view.backedTextInputView.font = [RCTFont updateFont:view.backedTextInputView.font withSize:json ?: @(defaultView.backedTextInputView.font.pointSize)]; -} -RCT_CUSTOM_VIEW_PROPERTY(fontWeight, NSString, __unused RCTTextField) -{ - view.backedTextInputView.font = [RCTFont updateFont:view.backedTextInputView.font withWeight:json]; // defaults to normal -} -RCT_CUSTOM_VIEW_PROPERTY(fontStyle, NSString, __unused RCTTextField) -{ - view.backedTextInputView.font = [RCTFont updateFont:view.backedTextInputView.font withStyle:json]; // defaults to normal -} -RCT_CUSTOM_VIEW_PROPERTY(fontFamily, NSString, RCTTextField) -{ - view.backedTextInputView.font = [RCTFont updateFont:view.backedTextInputView.font withFamily:json ?: defaultView.backedTextInputView.font.familyName]; -} + RCT_EXPORT_VIEW_PROPERTY(mostRecentEventCount, NSInteger) - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(RCTShadowView *)shadowView diff --git a/Libraries/Text/RCTTextInput.h b/Libraries/Text/RCTTextInput.h index 5531fca4e..47fcf4263 100644 --- a/Libraries/Text/RCTTextInput.h +++ b/Libraries/Text/RCTTextInput.h @@ -12,12 +12,14 @@ #import #import "RCTBackedTextInputViewProtocol.h" +#import "RCTFontAttributes.h" +#import "RCTFontAttributesDelegate.h" @class RCTBridge; @class RCTEventDispatcher; @class RCTTextSelection; -@interface RCTTextInput : RCTView { +@interface RCTTextInput : RCTView { @protected RCTBridge *_bridge; RCTEventDispatcher *_eventDispatcher; @@ -41,12 +43,16 @@ @property (nonatomic, copy) RCTDirectEventBlock onContentSizeChange; @property (nonatomic, copy) RCTDirectEventBlock onSelectionChange; +@property (nonatomic, readonly, strong) RCTFontAttributes *fontAttributes; + @property (nonatomic, assign) NSInteger mostRecentEventCount; @property (nonatomic, assign) BOOL blurOnSubmit; @property (nonatomic, assign) BOOL selectTextOnFocus; @property (nonatomic, assign) BOOL clearTextOnFocus; @property (nonatomic, copy) RCTTextSelection *selection; +- (void)setFont:(UIFont *)font; + - (void)invalidateContentSize; // Temporary exposure of particial `RCTBackedTextInputDelegate` support. diff --git a/Libraries/Text/RCTTextInput.m b/Libraries/Text/RCTTextInput.m index ed7bade62..d949437a4 100644 --- a/Libraries/Text/RCTTextInput.m +++ b/Libraries/Text/RCTTextInput.m @@ -9,11 +9,12 @@ #import "RCTTextInput.h" +#import #import #import #import -#import #import +#import #import #import "RCTTextSelection.h" @@ -29,6 +30,8 @@ if (self = [super initWithFrame:CGRectZero]) { _bridge = bridge; _eventDispatcher = bridge.eventDispatcher; + _fontAttributes = [[RCTFontAttributes alloc] initWithAccessibilityManager:bridge.accessibilityManager]; + _fontAttributes.delegate = self; } return self; @@ -44,6 +47,17 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame) return nil; } +- (void)setFont:(UIFont *)font +{ + self.backedTextInputView.font = font; + [self invalidateContentSize]; +} + +- (void)fontAttributesDidChangeWithFont:(UIFont *)font +{ + self.font = font; +} + #pragma mark - Properties - (void)setReactPaddingInsets:(UIEdgeInsets)reactPaddingInsets diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m index 3342e445e..f3f19067c 100644 --- a/Libraries/Text/RCTTextView.m +++ b/Libraries/Text/RCTTextView.m @@ -11,6 +11,7 @@ #import #import +#import #import #import #import @@ -54,8 +55,8 @@ _backedTextInput.scrollsToTop = NO; #endif _backedTextInput.scrollEnabled = YES; - _backedTextInput.textInputDelegate = self; + _backedTextInput.font = self.fontAttributes.font; [self addSubview:_backedTextInput]; } diff --git a/Libraries/Text/RCTTextViewManager.m b/Libraries/Text/RCTTextViewManager.m index 5f0fa6de9..814f2070f 100644 --- a/Libraries/Text/RCTTextViewManager.m +++ b/Libraries/Text/RCTTextViewManager.m @@ -35,11 +35,16 @@ RCT_EXPORT_MODULE() #pragma mark - Unified properties +RCT_REMAP_VIEW_PROPERTY(allowFontScaling, fontAttributes.allowFontScaling, BOOL) RCT_REMAP_VIEW_PROPERTY(autoCapitalize, backedTextInputView.autocapitalizationType, UITextAutocapitalizationType) RCT_REMAP_VIEW_PROPERTY(autoCorrect, backedTextInputView.autocorrectionType, UITextAutocorrectionType) RCT_REMAP_VIEW_PROPERTY(color, backedTextInputView.textColor, UIColor) RCT_REMAP_VIEW_PROPERTY(editable, backedTextInputView.editable, BOOL) RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, backedTextInputView.enablesReturnKeyAutomatically, BOOL) +RCT_REMAP_VIEW_PROPERTY(fontSize, fontAttributes.fontSize, NSNumber) +RCT_REMAP_VIEW_PROPERTY(fontWeight, fontAttributes.fontWeight, NSString) +RCT_REMAP_VIEW_PROPERTY(fontStyle, fontAttributes.fontStyle, NSString) +RCT_REMAP_VIEW_PROPERTY(fontFamily, fontAttributes.fontFamily, NSString) RCT_REMAP_VIEW_PROPERTY(keyboardAppearance, backedTextInputView.keyboardAppearance, UIKeyboardAppearance) RCT_REMAP_VIEW_PROPERTY(keyboardType, backedTextInputView.keyboardType, UIKeyboardType) RCT_REMAP_VIEW_PROPERTY(placeholder, backedTextInputView.placeholder, NSString) @@ -64,22 +69,6 @@ RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onTextInput, RCTDirectEventBlock) -RCT_CUSTOM_VIEW_PROPERTY(fontSize, NSNumber, RCTTextView) -{ - view.font = [RCTFont updateFont:view.font withSize:json ?: @(defaultView.font.pointSize)]; -} -RCT_CUSTOM_VIEW_PROPERTY(fontWeight, NSString, __unused RCTTextView) -{ - view.font = [RCTFont updateFont:view.font withWeight:json]; // defaults to normal -} -RCT_CUSTOM_VIEW_PROPERTY(fontStyle, NSString, __unused RCTTextView) -{ - view.font = [RCTFont updateFont:view.font withStyle:json]; // defaults to normal -} -RCT_CUSTOM_VIEW_PROPERTY(fontFamily, NSString, RCTTextView) -{ - view.font = [RCTFont updateFont:view.font withFamily:json ?: defaultView.font.familyName]; -} RCT_EXPORT_VIEW_PROPERTY(mostRecentEventCount, NSInteger) #if !TARGET_OS_TV