mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Proper type for RCTBackedTextInputViewProtocol::defaultTextAttributes
Summary: This diff changes how we apply default text attributes to backed text input. The original change in https://github.com/facebook/react-native/pull/23585 that introduced the `reactTextAttributes` field in for RCTBackedTextInputViewProtocol was great! Thank you Wu zhongwuzw ! However, there is one detail that needs to be changed. RCTBackedTextInputViewProtocol is designed to only abstract complexity of iOS text input components (UITextView and UITextField); it intentionally does not have any React-specific fields or types. Adding a field `RCTTextAttributes *reactTextAttributes;` violates this principle and make it hard to reuse this functionality in the new Fabric-powered TextInput. This diff changes the type of this prop from `RCTTextAttributes` to `NSDictionary<NSAttributedStringKey,id> *` (exact same type that UITextView and UITextField use). Reviewed By: cpojer Differential Revision: D17408501 fbshipit-source-id: 65f2bba119ccc30f22e87c28d0f8ea6f731cd365
This commit is contained in:
committed by
Facebook Github Bot
parent
9833ee7bc1
commit
e271fa190d
@@ -18,10 +18,9 @@
|
||||
UILabel *_placeholderView;
|
||||
UITextView *_detachedTextView;
|
||||
RCTBackedTextViewDelegateAdapter *_textInputDelegateAdapter;
|
||||
NSDictionary<NSAttributedStringKey, id> *_defaultTextAttributes;
|
||||
}
|
||||
|
||||
@synthesize reactTextAttributes = _reactTextAttributes;
|
||||
|
||||
static UIFont *defaultPlaceholderFont()
|
||||
{
|
||||
return [UIFont systemFontOfSize:17];
|
||||
@@ -44,7 +43,6 @@ static UIColor *defaultPlaceholderColor()
|
||||
_placeholderView = [[UILabel alloc] initWithFrame:self.bounds];
|
||||
_placeholderView.isAccessibilityElement = NO;
|
||||
_placeholderView.numberOfLines = 0;
|
||||
_placeholderView.textColor = defaultPlaceholderColor();
|
||||
[self addSubview:_placeholderView];
|
||||
|
||||
_textInputDelegateAdapter = [[RCTBackedTextViewDelegateAdapter alloc] initWithTextView:self];
|
||||
@@ -91,35 +89,31 @@ static UIColor *defaultPlaceholderColor()
|
||||
- (void)setPlaceholder:(NSString *)placeholder
|
||||
{
|
||||
_placeholder = placeholder;
|
||||
_placeholderView.attributedText = [[NSAttributedString alloc] initWithString:_placeholder ?: @"" attributes:[self placeholderEffectiveTextAttributes]];
|
||||
[self _updatePlaceholder];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderColor:(UIColor *)placeholderColor
|
||||
{
|
||||
_placeholderColor = placeholderColor;
|
||||
_placeholderView.textColor = _placeholderColor ?: defaultPlaceholderColor();
|
||||
[self _updatePlaceholder];
|
||||
}
|
||||
|
||||
- (void)setReactTextAttributes:(RCTTextAttributes *)reactTextAttributes
|
||||
- (void)setDefaultTextAttributes:(NSDictionary<NSAttributedStringKey, id> *)defaultTextAttributes
|
||||
{
|
||||
if ([reactTextAttributes isEqual:_reactTextAttributes]) {
|
||||
return;
|
||||
}
|
||||
self.typingAttributes = reactTextAttributes.effectiveTextAttributes;
|
||||
_reactTextAttributes = reactTextAttributes;
|
||||
// Update placeholder text attributes
|
||||
[self setPlaceholder:_placeholder];
|
||||
_defaultTextAttributes = defaultTextAttributes;
|
||||
self.typingAttributes = defaultTextAttributes;
|
||||
[self _updatePlaceholder];
|
||||
}
|
||||
|
||||
- (RCTTextAttributes *)reactTextAttributes
|
||||
- (NSDictionary<NSAttributedStringKey, id> *)defaultTextAttributes
|
||||
{
|
||||
return _reactTextAttributes;
|
||||
return _defaultTextAttributes;
|
||||
}
|
||||
|
||||
- (void)textDidChange
|
||||
{
|
||||
_textWasPasted = NO;
|
||||
[self invalidatePlaceholderVisibility];
|
||||
[self _invalidatePlaceholderVisibility];
|
||||
}
|
||||
|
||||
#pragma mark - Overrides
|
||||
@@ -127,7 +121,7 @@ static UIColor *defaultPlaceholderColor()
|
||||
- (void)setFont:(UIFont *)font
|
||||
{
|
||||
[super setFont:font];
|
||||
_placeholderView.font = font ?: defaultPlaceholderFont();
|
||||
[self _updatePlaceholder];
|
||||
}
|
||||
|
||||
- (void)setTextAlignment:(NSTextAlignment)textAlignment
|
||||
@@ -195,7 +189,7 @@ static UIColor *defaultPlaceholderColor()
|
||||
UIEdgeInsets textContainerInset = self.textContainerInset;
|
||||
NSString *placeholder = self.placeholder ?: @"";
|
||||
CGSize maxPlaceholderSize = CGSizeMake(UIEdgeInsetsInsetRect(self.bounds, textContainerInset).size.width, CGFLOAT_MAX);
|
||||
CGSize placeholderSize = [placeholder boundingRectWithSize:maxPlaceholderSize options:NSStringDrawingUsesLineFragmentOrigin attributes:[self placeholderEffectiveTextAttributes] context:nil].size;
|
||||
CGSize placeholderSize = [placeholder boundingRectWithSize:maxPlaceholderSize options:NSStringDrawingUsesLineFragmentOrigin attributes:[self _placeholderTextAttributes] context:nil].size;
|
||||
placeholderSize = CGSizeMake(RCTCeilPixelValue(placeholderSize.width), RCTCeilPixelValue(placeholderSize.height));
|
||||
placeholderSize.width += textContainerInset.left + textContainerInset.right;
|
||||
placeholderSize.height += textContainerInset.top + textContainerInset.bottom;
|
||||
@@ -253,25 +247,28 @@ static UIColor *defaultPlaceholderColor()
|
||||
|
||||
#pragma mark - Placeholder
|
||||
|
||||
- (void)invalidatePlaceholderVisibility
|
||||
- (void)_invalidatePlaceholderVisibility
|
||||
{
|
||||
BOOL isVisible = _placeholder.length != 0 && self.attributedText.length == 0;
|
||||
_placeholderView.hidden = !isVisible;
|
||||
}
|
||||
|
||||
- (NSDictionary<NSAttributedStringKey, id> *)placeholderEffectiveTextAttributes
|
||||
- (void)_updatePlaceholder
|
||||
{
|
||||
NSMutableDictionary<NSAttributedStringKey, id> *effectiveTextAttributes = [NSMutableDictionary dictionaryWithDictionary:@{
|
||||
NSFontAttributeName: _reactTextAttributes.effectiveFont ?: defaultPlaceholderFont(),
|
||||
NSForegroundColorAttributeName: self.placeholderColor ?: defaultPlaceholderColor(),
|
||||
NSKernAttributeName:isnan(_reactTextAttributes.letterSpacing) ? @0 : @(_reactTextAttributes.letterSpacing)
|
||||
}];
|
||||
NSParagraphStyle *paragraphStyle = [_reactTextAttributes effectiveParagraphStyle];
|
||||
if (paragraphStyle) {
|
||||
effectiveTextAttributes[NSParagraphStyleAttributeName] = paragraphStyle;
|
||||
_placeholderView.attributedText = [[NSAttributedString alloc] initWithString:_placeholder ?: @"" attributes:[self _placeholderTextAttributes]];
|
||||
}
|
||||
|
||||
- (NSDictionary<NSAttributedStringKey, id> *)_placeholderTextAttributes
|
||||
{
|
||||
NSMutableDictionary<NSAttributedStringKey, id> *textAttributes = [_defaultTextAttributes mutableCopy] ?: [NSMutableDictionary new];
|
||||
|
||||
[textAttributes setValue:self.placeholderColor ?: defaultPlaceholderColor() forKey:NSForegroundColorAttributeName];
|
||||
|
||||
if (![textAttributes objectForKey:NSFontAttributeName]) {
|
||||
[textAttributes setValue:defaultPlaceholderFont() forKey:NSFontAttributeName];
|
||||
}
|
||||
|
||||
return [effectiveTextAttributes copy];
|
||||
|
||||
return textAttributes;
|
||||
}
|
||||
|
||||
#pragma mark - Utility Methods
|
||||
|
||||
@@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, strong, nullable) UIView *inputAccessoryView;
|
||||
@property (nonatomic, weak, nullable) id<RCTBackedTextInputDelegate> textInputDelegate;
|
||||
@property (nonatomic, readonly) CGSize contentSize;
|
||||
@property (nonatomic, strong, nullable) RCTTextAttributes *reactTextAttributes;
|
||||
@property (nonatomic, strong, nullable) NSDictionary<NSAttributedStringKey,id> *defaultTextAttributes;
|
||||
|
||||
// This protocol disallows direct access to `selectedTextRange` property because
|
||||
// unwise usage of it can break the `delegate` behavior. So, we always have to
|
||||
|
||||
@@ -47,6 +47,16 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)didSetProps:(NSArray<NSString *> *)changedProps
|
||||
{
|
||||
[super didSetProps:changedProps];
|
||||
|
||||
// `backgroundColor` and `opacity` are being applied directly to a UIView,
|
||||
// therefore we need to exclude them from base `textAttributes`.
|
||||
self.textAttributes.backgroundColor = nil;
|
||||
self.textAttributes.opacity = NAN;
|
||||
}
|
||||
|
||||
- (void)layoutSubviewsWithContext:(RCTLayoutContext)layoutContext
|
||||
{
|
||||
// Do nothing.
|
||||
|
||||
@@ -67,7 +67,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
|
||||
- (void)enforceTextAttributesIfNeeded
|
||||
{
|
||||
id<RCTBackedTextInputViewProtocol> backedTextInputView = self.backedTextInputView;
|
||||
backedTextInputView.reactTextAttributes = _textAttributes;
|
||||
backedTextInputView.defaultTextAttributes = [_textAttributes effectiveTextAttributes];
|
||||
}
|
||||
|
||||
- (void)setReactPaddingInsets:(UIEdgeInsets)reactPaddingInsets
|
||||
|
||||
@@ -15,10 +15,9 @@
|
||||
|
||||
@implementation RCTUITextField {
|
||||
RCTBackedTextFieldDelegateAdapter *_textInputDelegateAdapter;
|
||||
NSDictionary<NSAttributedStringKey, id> *_defaultTextAttributes;
|
||||
}
|
||||
|
||||
@synthesize reactTextAttributes = _reactTextAttributes;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
@@ -72,29 +71,22 @@
|
||||
[self _updatePlaceholder];
|
||||
}
|
||||
|
||||
- (void)setReactTextAttributes:(RCTTextAttributes *)reactTextAttributes
|
||||
- (void)setDefaultTextAttributes:(NSDictionary<NSAttributedStringKey, id> *)defaultTextAttributes
|
||||
{
|
||||
if ([reactTextAttributes isEqual:_reactTextAttributes]) {
|
||||
return;
|
||||
}
|
||||
self.defaultTextAttributes = reactTextAttributes.effectiveTextAttributes;
|
||||
_reactTextAttributes = reactTextAttributes;
|
||||
_defaultTextAttributes = defaultTextAttributes;
|
||||
[super setDefaultTextAttributes:defaultTextAttributes];
|
||||
[self _updatePlaceholder];
|
||||
}
|
||||
|
||||
- (RCTTextAttributes *)reactTextAttributes
|
||||
- (NSDictionary<NSAttributedStringKey, id> *)defaultTextAttributes
|
||||
{
|
||||
return _reactTextAttributes;
|
||||
return _defaultTextAttributes;
|
||||
}
|
||||
|
||||
- (void)_updatePlaceholder
|
||||
{
|
||||
if (self.placeholder == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.attributedPlaceholder = [[NSAttributedString alloc] initWithString:self.placeholder
|
||||
attributes:[self placeholderEffectiveTextAttributes]];
|
||||
self.attributedPlaceholder = [[NSAttributedString alloc] initWithString:self.placeholder ?: @""
|
||||
attributes:[self _placeholderTextAttributes]];
|
||||
}
|
||||
|
||||
- (BOOL)isEditable
|
||||
@@ -119,24 +111,17 @@
|
||||
|
||||
#pragma mark - Placeholder
|
||||
|
||||
- (NSDictionary<NSAttributedStringKey, id> *)placeholderEffectiveTextAttributes
|
||||
- (NSDictionary<NSAttributedStringKey, id> *)_placeholderTextAttributes
|
||||
{
|
||||
NSMutableDictionary<NSAttributedStringKey, id> *effectiveTextAttributes = [NSMutableDictionary dictionary];
|
||||
|
||||
if (_placeholderColor) {
|
||||
effectiveTextAttributes[NSForegroundColorAttributeName] = _placeholderColor;
|
||||
NSMutableDictionary<NSAttributedStringKey, id> *textAttributes = [_defaultTextAttributes mutableCopy] ?: [NSMutableDictionary new];
|
||||
|
||||
if (self.placeholderColor) {
|
||||
[textAttributes setValue:self.placeholderColor forKey:NSForegroundColorAttributeName];
|
||||
} else {
|
||||
[textAttributes removeObjectForKey:NSForegroundColorAttributeName];
|
||||
}
|
||||
// Kerning
|
||||
if (!isnan(_reactTextAttributes.letterSpacing)) {
|
||||
effectiveTextAttributes[NSKernAttributeName] = @(_reactTextAttributes.letterSpacing);
|
||||
}
|
||||
|
||||
NSParagraphStyle *paragraphStyle = [_reactTextAttributes effectiveParagraphStyle];
|
||||
if (paragraphStyle) {
|
||||
effectiveTextAttributes[NSParagraphStyleAttributeName] = paragraphStyle;
|
||||
}
|
||||
|
||||
return [effectiveTextAttributes copy];
|
||||
|
||||
return textAttributes;
|
||||
}
|
||||
|
||||
#pragma mark - Context Menu
|
||||
@@ -161,7 +146,6 @@
|
||||
return [super caretRectForPosition:position];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Positioning Overrides
|
||||
|
||||
- (CGRect)textRectForBounds:(CGRect)bounds
|
||||
@@ -215,7 +199,7 @@
|
||||
{
|
||||
// Note: `placeholder` defines intrinsic size for `<TextInput>`.
|
||||
NSString *text = self.placeholder ?: @"";
|
||||
CGSize size = [text sizeWithAttributes:[self placeholderEffectiveTextAttributes]];
|
||||
CGSize size = [text sizeWithAttributes:[self _placeholderTextAttributes]];
|
||||
size = CGSizeMake(RCTCeilPixelValue(size.width), RCTCeilPixelValue(size.height));
|
||||
size.width += _textContainerInset.left + _textContainerInset.right;
|
||||
size.height += _textContainerInset.top + _textContainerInset.bottom;
|
||||
|
||||
Reference in New Issue
Block a user