initial commit taken from gitlab.lrz.de

This commit is contained in:
privatereese
2018-08-24 18:09:42 +02:00
parent ae54ed4c48
commit fc05486403
28494 changed files with 2159823 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTShadowView.h>
#import "RCTTextAttributes.h"
NS_ASSUME_NONNULL_BEGIN
extern NSString *const RCTBaseTextShadowViewEmbeddedShadowViewAttributeName;
@interface RCTBaseTextShadowView : RCTShadowView
@property (nonatomic, strong) RCTTextAttributes *textAttributes;
- (NSAttributedString *)attributedTextWithBaseTextAttributes:(nullable RCTTextAttributes *)baseTextAttributes;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,123 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextShadowView.h"
#import <React/RCTShadowView+Layout.h>
#import "RCTRawTextShadowView.h"
#import "RCTVirtualTextShadowView.h"
NSString *const RCTBaseTextShadowViewEmbeddedShadowViewAttributeName = @"RCTBaseTextShadowViewEmbeddedShadowViewAttributeName";
@implementation RCTBaseTextShadowView
{
NSAttributedString *_Nullable _cachedAttributedText;
RCTTextAttributes *_Nullable _cachedTextAttributes;
}
- (instancetype)init
{
if (self = [super init]) {
_textAttributes = [RCTTextAttributes new];
}
return self;
}
- (void)setReactTag:(NSNumber *)reactTag
{
[super setReactTag:reactTag];
_textAttributes.tag = reactTag;
}
#pragma mark - attributedString
- (NSAttributedString *)attributedTextWithBaseTextAttributes:(nullable RCTTextAttributes *)baseTextAttributes
{
RCTTextAttributes *textAttributes;
if (baseTextAttributes) {
textAttributes = [baseTextAttributes copy];
[textAttributes applyTextAttributes:self.textAttributes];
} else {
textAttributes = [self.textAttributes copy];
}
if (_cachedAttributedText && [_cachedTextAttributes isEqual:textAttributes]) {
return _cachedAttributedText;
}
NSMutableAttributedString *attributedText = [NSMutableAttributedString new];
[attributedText beginEditing];
for (RCTShadowView *shadowView in self.reactSubviews) {
// Special Case: RCTRawTextShadowView
if ([shadowView isKindOfClass:[RCTRawTextShadowView class]]) {
RCTRawTextShadowView *rawTextShadowView = (RCTRawTextShadowView *)shadowView;
NSString *text = rawTextShadowView.text;
if (text) {
NSAttributedString *rawTextAttributedString =
[[NSAttributedString alloc] initWithString:rawTextShadowView.text
attributes:textAttributes.effectiveTextAttributes];
[attributedText appendAttributedString:rawTextAttributedString];
}
continue;
}
// Special Case: RCTBaseTextShadowView
if ([shadowView isKindOfClass:[RCTBaseTextShadowView class]]) {
RCTBaseTextShadowView *baseTextShadowView = (RCTBaseTextShadowView *)shadowView;
NSAttributedString *baseTextAttributedString =
[baseTextShadowView attributedTextWithBaseTextAttributes:textAttributes];
[attributedText appendAttributedString:baseTextAttributedString];
continue;
}
// Generic Case: Any RCTShadowView
NSTextAttachment *attachment = [NSTextAttachment new];
NSMutableAttributedString *embeddedShadowViewAttributedString = [NSMutableAttributedString new];
[embeddedShadowViewAttributedString beginEditing];
[embeddedShadowViewAttributedString appendAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]];
[embeddedShadowViewAttributedString addAttribute:RCTBaseTextShadowViewEmbeddedShadowViewAttributeName
value:shadowView
range:(NSRange){0, embeddedShadowViewAttributedString.length}];
[embeddedShadowViewAttributedString endEditing];
[attributedText appendAttributedString:embeddedShadowViewAttributedString];
}
[attributedText endEditing];
[self clearLayout];
_cachedAttributedText = [attributedText copy];
_cachedTextAttributes = textAttributes;
return _cachedAttributedText;
}
- (void)dirtyLayout
{
[super dirtyLayout];
_cachedAttributedText = nil;
_cachedTextAttributes = nil;
}
- (void)didUpdateReactSubviews
{
[super didUpdateReactSubviews];
[self dirtyLayout];
}
- (void)didSetProps:(NSArray<NSString *> *)changedProps
{
[super didSetProps:changedProps];
[self dirtyLayout];
}
@end

View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTViewManager.h>
NS_ASSUME_NONNULL_BEGIN
@interface RCTBaseTextViewManager : RCTViewManager
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextViewManager.h"
@implementation RCTBaseTextViewManager
RCT_EXPORT_MODULE(RCTBaseText)
- (UIView *)view
{
RCTAssert(NO, @"The `-[RCTBaseTextViewManager view]` property must be overridden in subclass.");
return nil;
}
- (RCTShadowView *)shadowView
{
RCTAssert(NO, @"The `-[RCTBaseTextViewManager shadowView]` property must be overridden in subclass.");
return nil;
}
#pragma mark - Text Attributes
// Color
RCT_REMAP_SHADOW_PROPERTY(color, textAttributes.foregroundColor, UIColor)
RCT_REMAP_SHADOW_PROPERTY(backgroundColor, textAttributes.backgroundColor, UIColor)
RCT_REMAP_SHADOW_PROPERTY(opacity, textAttributes.opacity, CGFloat)
// Font
RCT_REMAP_SHADOW_PROPERTY(fontFamily, textAttributes.fontFamily, NSString)
RCT_REMAP_SHADOW_PROPERTY(fontSize, textAttributes.fontSize, CGFloat)
RCT_REMAP_SHADOW_PROPERTY(fontWeight, textAttributes.fontWeight, NSString)
RCT_REMAP_SHADOW_PROPERTY(fontStyle, textAttributes.fontStyle, NSString)
RCT_REMAP_SHADOW_PROPERTY(fontVariant, textAttributes.fontVariant, NSArray)
RCT_REMAP_SHADOW_PROPERTY(allowFontScaling, textAttributes.allowFontScaling, BOOL)
RCT_REMAP_SHADOW_PROPERTY(letterSpacing, textAttributes.letterSpacing, CGFloat)
// Paragraph Styles
RCT_REMAP_SHADOW_PROPERTY(lineHeight, textAttributes.lineHeight, CGFloat)
RCT_REMAP_SHADOW_PROPERTY(textAlign, textAttributes.alignment, NSTextAlignment)
RCT_REMAP_SHADOW_PROPERTY(writingDirection, textAttributes.baseWritingDirection, NSWritingDirection)
// Decoration
RCT_REMAP_SHADOW_PROPERTY(textDecorationColor, textAttributes.textDecorationColor, UIColor)
RCT_REMAP_SHADOW_PROPERTY(textDecorationStyle, textAttributes.textDecorationStyle, NSUnderlineStyle)
RCT_REMAP_SHADOW_PROPERTY(textDecorationLine, textAttributes.textDecorationLine, RCTTextDecorationLineType)
// Shadow
RCT_REMAP_SHADOW_PROPERTY(textShadowOffset, textAttributes.textShadowOffset, CGSize)
RCT_REMAP_SHADOW_PROPERTY(textShadowRadius, textAttributes.textShadowRadius, CGFloat)
RCT_REMAP_SHADOW_PROPERTY(textShadowColor, textAttributes.textShadowColor, UIColor)
// Special
RCT_REMAP_SHADOW_PROPERTY(isHighlighted, textAttributes.isHighlighted, BOOL)
@end

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTConvert.h>
NS_ASSUME_NONNULL_BEGIN
@interface RCTConvert (Text)
+ (UITextAutocorrectionType)UITextAutocorrectionType:(nullable id)json;
+ (UITextSpellCheckingType)UITextSpellCheckingType:(nullable id)json;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTConvert+Text.h"
@implementation RCTConvert (Text)
+ (UITextAutocorrectionType)UITextAutocorrectionType:(id)json
{
return
json == nil ? UITextAutocorrectionTypeDefault :
[RCTConvert BOOL:json] ? UITextAutocorrectionTypeYes :
UITextAutocorrectionTypeNo;
}
+ (UITextSpellCheckingType)UITextSpellCheckingType:(id)json
{
return
json == nil ? UITextSpellCheckingTypeDefault :
[RCTConvert BOOL:json] ? UITextSpellCheckingTypeYes :
UITextSpellCheckingTypeNo;
}
@end

View File

@@ -0,0 +1,689 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
5956B130200FEBAA008D9D16 /* RCTRawTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B0FD200FEBA9008D9D16 /* RCTRawTextShadowView.m */; };
5956B131200FEBAA008D9D16 /* RCTRawTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B0FE200FEBA9008D9D16 /* RCTRawTextViewManager.m */; };
5956B132200FEBAA008D9D16 /* RCTSinglelineTextInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B101200FEBA9008D9D16 /* RCTSinglelineTextInputView.m */; };
5956B133200FEBAA008D9D16 /* RCTUITextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B103200FEBA9008D9D16 /* RCTUITextField.m */; };
5956B134200FEBAA008D9D16 /* RCTSinglelineTextInputViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B106200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.m */; };
5956B135200FEBAA008D9D16 /* RCTBaseTextInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B10A200FEBA9008D9D16 /* RCTBaseTextInputView.m */; };
5956B136200FEBAA008D9D16 /* RCTBackedTextInputDelegateAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B10D200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.m */; };
5956B137200FEBAA008D9D16 /* RCTBaseTextInputShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B10F200FEBA9008D9D16 /* RCTBaseTextInputShadowView.m */; };
5956B138200FEBAA008D9D16 /* RCTTextSelection.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B110200FEBA9008D9D16 /* RCTTextSelection.m */; };
5956B139200FEBAA008D9D16 /* RCTBaseTextInputViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B111200FEBA9008D9D16 /* RCTBaseTextInputViewManager.m */; };
5956B13A200FEBAA008D9D16 /* RCTMultilineTextInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B115200FEBA9008D9D16 /* RCTMultilineTextInputView.m */; };
5956B13B200FEBAA008D9D16 /* RCTMultilineTextInputViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B118200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.m */; };
5956B13C200FEBAA008D9D16 /* RCTUITextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B119200FEBA9008D9D16 /* RCTUITextView.m */; };
5956B13D200FEBAA008D9D16 /* RCTBaseTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B11E200FEBA9008D9D16 /* RCTBaseTextShadowView.m */; };
5956B13E200FEBAA008D9D16 /* RCTBaseTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B11F200FEBA9008D9D16 /* RCTBaseTextViewManager.m */; };
5956B13F200FEBAA008D9D16 /* RCTTextAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B120200FEBA9008D9D16 /* RCTTextAttributes.m */; };
5956B140200FEBAA008D9D16 /* RCTTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B122200FEBAA008D9D16 /* RCTTextShadowView.m */; };
5956B141200FEBAA008D9D16 /* NSTextStorage+FontScaling.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B125200FEBAA008D9D16 /* NSTextStorage+FontScaling.m */; };
5956B142200FEBAA008D9D16 /* RCTTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B127200FEBAA008D9D16 /* RCTTextViewManager.m */; };
5956B143200FEBAA008D9D16 /* RCTTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B128200FEBAA008D9D16 /* RCTTextView.m */; };
5956B144200FEBAA008D9D16 /* RCTVirtualTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B12B200FEBAA008D9D16 /* RCTVirtualTextViewManager.m */; };
5956B145200FEBAA008D9D16 /* RCTVirtualTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B12E200FEBAA008D9D16 /* RCTVirtualTextShadowView.m */; };
5956B146200FEBAA008D9D16 /* RCTConvert+Text.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B12F200FEBAA008D9D16 /* RCTConvert+Text.m */; };
5956B160200FF324008D9D16 /* RCTBaseTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B11D200FEBA9008D9D16 /* RCTBaseTextShadowView.h */; };
5956B161200FF324008D9D16 /* RCTBaseTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B11C200FEBA9008D9D16 /* RCTBaseTextViewManager.h */; };
5956B162200FF324008D9D16 /* RCTRawTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B0FC200FEBA9008D9D16 /* RCTRawTextShadowView.h */; };
5956B163200FF324008D9D16 /* RCTRawTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B0FB200FEBA9008D9D16 /* RCTRawTextViewManager.h */; };
5956B164200FF324008D9D16 /* RCTConvert+Text.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B0F9200FEBA9008D9D16 /* RCTConvert+Text.h */; };
5956B165200FF324008D9D16 /* RCTTextAttributes.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B11A200FEBA9008D9D16 /* RCTTextAttributes.h */; };
5956B166200FF324008D9D16 /* NSTextStorage+FontScaling.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B129200FEBAA008D9D16 /* NSTextStorage+FontScaling.h */; };
5956B167200FF324008D9D16 /* RCTTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B126200FEBAA008D9D16 /* RCTTextShadowView.h */; };
5956B168200FF324008D9D16 /* RCTTextView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B123200FEBAA008D9D16 /* RCTTextView.h */; };
5956B169200FF324008D9D16 /* RCTTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B124200FEBAA008D9D16 /* RCTTextViewManager.h */; };
5956B16A200FF324008D9D16 /* RCTMultilineTextInputView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B117200FEBA9008D9D16 /* RCTMultilineTextInputView.h */; };
5956B16B200FF324008D9D16 /* RCTMultilineTextInputViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B114200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.h */; };
5956B16C200FF324008D9D16 /* RCTUITextView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B116200FEBA9008D9D16 /* RCTUITextView.h */; };
5956B16D200FF324008D9D16 /* RCTBackedTextInputDelegate.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B10C200FEBA9008D9D16 /* RCTBackedTextInputDelegate.h */; };
5956B16E200FF324008D9D16 /* RCTBackedTextInputDelegateAdapter.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B107200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.h */; };
5956B16F200FF324008D9D16 /* RCTBackedTextInputViewProtocol.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B112200FEBA9008D9D16 /* RCTBackedTextInputViewProtocol.h */; };
5956B170200FF324008D9D16 /* RCTBaseTextInputShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B109200FEBA9008D9D16 /* RCTBaseTextInputShadowView.h */; };
5956B171200FF324008D9D16 /* RCTBaseTextInputView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B10E200FEBA9008D9D16 /* RCTBaseTextInputView.h */; };
5956B172200FF324008D9D16 /* RCTBaseTextInputViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B10B200FEBA9008D9D16 /* RCTBaseTextInputViewManager.h */; };
5956B173200FF324008D9D16 /* RCTTextSelection.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B108200FEBA9008D9D16 /* RCTTextSelection.h */; };
5956B174200FF324008D9D16 /* RCTSinglelineTextInputView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B104200FEBA9008D9D16 /* RCTSinglelineTextInputView.h */; };
5956B175200FF324008D9D16 /* RCTSinglelineTextInputViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B102200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.h */; };
5956B176200FF324008D9D16 /* RCTUITextField.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B105200FEBA9008D9D16 /* RCTUITextField.h */; };
5956B177200FF324008D9D16 /* RCTVirtualTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B12C200FEBAA008D9D16 /* RCTVirtualTextShadowView.h */; };
5956B178200FF324008D9D16 /* RCTVirtualTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B12D200FEBAA008D9D16 /* RCTVirtualTextViewManager.h */; };
5956B179200FF338008D9D16 /* RCTBaseTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B11D200FEBA9008D9D16 /* RCTBaseTextShadowView.h */; };
5956B17A200FF338008D9D16 /* RCTBaseTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B11C200FEBA9008D9D16 /* RCTBaseTextViewManager.h */; };
5956B17B200FF338008D9D16 /* RCTRawTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B0FC200FEBA9008D9D16 /* RCTRawTextShadowView.h */; };
5956B17C200FF338008D9D16 /* RCTRawTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B0FB200FEBA9008D9D16 /* RCTRawTextViewManager.h */; };
5956B17D200FF338008D9D16 /* RCTConvert+Text.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B0F9200FEBA9008D9D16 /* RCTConvert+Text.h */; };
5956B17E200FF338008D9D16 /* RCTTextAttributes.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B11A200FEBA9008D9D16 /* RCTTextAttributes.h */; };
5956B17F200FF338008D9D16 /* NSTextStorage+FontScaling.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B129200FEBAA008D9D16 /* NSTextStorage+FontScaling.h */; };
5956B180200FF338008D9D16 /* RCTTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B126200FEBAA008D9D16 /* RCTTextShadowView.h */; };
5956B181200FF338008D9D16 /* RCTTextView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B123200FEBAA008D9D16 /* RCTTextView.h */; };
5956B182200FF338008D9D16 /* RCTTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B124200FEBAA008D9D16 /* RCTTextViewManager.h */; };
5956B183200FF338008D9D16 /* RCTMultilineTextInputView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B117200FEBA9008D9D16 /* RCTMultilineTextInputView.h */; };
5956B184200FF338008D9D16 /* RCTMultilineTextInputViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B114200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.h */; };
5956B185200FF338008D9D16 /* RCTUITextView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B116200FEBA9008D9D16 /* RCTUITextView.h */; };
5956B186200FF338008D9D16 /* RCTBackedTextInputDelegate.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B10C200FEBA9008D9D16 /* RCTBackedTextInputDelegate.h */; };
5956B187200FF338008D9D16 /* RCTBackedTextInputDelegateAdapter.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B107200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.h */; };
5956B188200FF338008D9D16 /* RCTBackedTextInputViewProtocol.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B112200FEBA9008D9D16 /* RCTBackedTextInputViewProtocol.h */; };
5956B189200FF338008D9D16 /* RCTBaseTextInputShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B109200FEBA9008D9D16 /* RCTBaseTextInputShadowView.h */; };
5956B18A200FF338008D9D16 /* RCTBaseTextInputView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B10E200FEBA9008D9D16 /* RCTBaseTextInputView.h */; };
5956B18B200FF338008D9D16 /* RCTBaseTextInputViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B10B200FEBA9008D9D16 /* RCTBaseTextInputViewManager.h */; };
5956B18C200FF338008D9D16 /* RCTTextSelection.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B108200FEBA9008D9D16 /* RCTTextSelection.h */; };
5956B18D200FF338008D9D16 /* RCTSinglelineTextInputView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B104200FEBA9008D9D16 /* RCTSinglelineTextInputView.h */; };
5956B18E200FF338008D9D16 /* RCTSinglelineTextInputViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B102200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.h */; };
5956B18F200FF338008D9D16 /* RCTUITextField.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B105200FEBA9008D9D16 /* RCTUITextField.h */; };
5956B190200FF338008D9D16 /* RCTVirtualTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B12C200FEBAA008D9D16 /* RCTVirtualTextShadowView.h */; };
5956B191200FF338008D9D16 /* RCTVirtualTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B12D200FEBAA008D9D16 /* RCTVirtualTextViewManager.h */; };
5956B192200FF35C008D9D16 /* RCTBaseTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B11E200FEBA9008D9D16 /* RCTBaseTextShadowView.m */; };
5956B193200FF35C008D9D16 /* RCTBaseTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B11F200FEBA9008D9D16 /* RCTBaseTextViewManager.m */; };
5956B194200FF35C008D9D16 /* RCTRawTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B0FD200FEBA9008D9D16 /* RCTRawTextShadowView.m */; };
5956B195200FF35C008D9D16 /* RCTRawTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B0FE200FEBA9008D9D16 /* RCTRawTextViewManager.m */; };
5956B196200FF35C008D9D16 /* RCTConvert+Text.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B12F200FEBAA008D9D16 /* RCTConvert+Text.m */; };
5956B197200FF35C008D9D16 /* RCTTextAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B120200FEBA9008D9D16 /* RCTTextAttributes.m */; };
5956B198200FF35C008D9D16 /* NSTextStorage+FontScaling.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B125200FEBAA008D9D16 /* NSTextStorage+FontScaling.m */; };
5956B199200FF35C008D9D16 /* RCTTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B122200FEBAA008D9D16 /* RCTTextShadowView.m */; };
5956B19A200FF35C008D9D16 /* RCTTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B128200FEBAA008D9D16 /* RCTTextView.m */; };
5956B19B200FF35C008D9D16 /* RCTTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B127200FEBAA008D9D16 /* RCTTextViewManager.m */; };
5956B19C200FF35C008D9D16 /* RCTMultilineTextInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B115200FEBA9008D9D16 /* RCTMultilineTextInputView.m */; };
5956B19D200FF35C008D9D16 /* RCTMultilineTextInputViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B118200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.m */; };
5956B19E200FF35C008D9D16 /* RCTUITextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B119200FEBA9008D9D16 /* RCTUITextView.m */; };
5956B19F200FF35C008D9D16 /* RCTBackedTextInputDelegateAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B10D200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.m */; };
5956B1A0200FF35C008D9D16 /* RCTBaseTextInputShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B10F200FEBA9008D9D16 /* RCTBaseTextInputShadowView.m */; };
5956B1A1200FF35C008D9D16 /* RCTBaseTextInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B10A200FEBA9008D9D16 /* RCTBaseTextInputView.m */; };
5956B1A2200FF35C008D9D16 /* RCTBaseTextInputViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B111200FEBA9008D9D16 /* RCTBaseTextInputViewManager.m */; };
5956B1A3200FF35C008D9D16 /* RCTTextSelection.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B110200FEBA9008D9D16 /* RCTTextSelection.m */; };
5956B1A4200FF35C008D9D16 /* RCTSinglelineTextInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B101200FEBA9008D9D16 /* RCTSinglelineTextInputView.m */; };
5956B1A5200FF35C008D9D16 /* RCTSinglelineTextInputViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B106200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.m */; };
5956B1A6200FF35C008D9D16 /* RCTUITextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B103200FEBA9008D9D16 /* RCTUITextField.m */; };
5956B1A7200FF35C008D9D16 /* RCTVirtualTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B12E200FEBAA008D9D16 /* RCTVirtualTextShadowView.m */; };
5956B1A8200FF35C008D9D16 /* RCTVirtualTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B12B200FEBAA008D9D16 /* RCTVirtualTextViewManager.m */; };
8F2807C7202D2B6B005D65E6 /* RCTInputAccessoryViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F2807C1202D2B6A005D65E6 /* RCTInputAccessoryViewManager.m */; };
8F2807C8202D2B6B005D65E6 /* RCTInputAccessoryView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F2807C3202D2B6A005D65E6 /* RCTInputAccessoryView.m */; };
8F2807C9202D2B6B005D65E6 /* RCTInputAccessoryViewContent.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F2807C5202D2B6B005D65E6 /* RCTInputAccessoryViewContent.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
599DF25E1F0306540079B53E /* Copy Headers */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = include/RCTText;
dstSubfolderSpec = 16;
files = (
5956B160200FF324008D9D16 /* RCTBaseTextShadowView.h in Copy Headers */,
5956B161200FF324008D9D16 /* RCTBaseTextViewManager.h in Copy Headers */,
5956B162200FF324008D9D16 /* RCTRawTextShadowView.h in Copy Headers */,
5956B163200FF324008D9D16 /* RCTRawTextViewManager.h in Copy Headers */,
5956B164200FF324008D9D16 /* RCTConvert+Text.h in Copy Headers */,
5956B165200FF324008D9D16 /* RCTTextAttributes.h in Copy Headers */,
5956B166200FF324008D9D16 /* NSTextStorage+FontScaling.h in Copy Headers */,
5956B167200FF324008D9D16 /* RCTTextShadowView.h in Copy Headers */,
5956B168200FF324008D9D16 /* RCTTextView.h in Copy Headers */,
5956B169200FF324008D9D16 /* RCTTextViewManager.h in Copy Headers */,
5956B16A200FF324008D9D16 /* RCTMultilineTextInputView.h in Copy Headers */,
5956B16B200FF324008D9D16 /* RCTMultilineTextInputViewManager.h in Copy Headers */,
5956B16C200FF324008D9D16 /* RCTUITextView.h in Copy Headers */,
5956B16D200FF324008D9D16 /* RCTBackedTextInputDelegate.h in Copy Headers */,
5956B16E200FF324008D9D16 /* RCTBackedTextInputDelegateAdapter.h in Copy Headers */,
5956B16F200FF324008D9D16 /* RCTBackedTextInputViewProtocol.h in Copy Headers */,
5956B170200FF324008D9D16 /* RCTBaseTextInputShadowView.h in Copy Headers */,
5956B171200FF324008D9D16 /* RCTBaseTextInputView.h in Copy Headers */,
5956B172200FF324008D9D16 /* RCTBaseTextInputViewManager.h in Copy Headers */,
5956B173200FF324008D9D16 /* RCTTextSelection.h in Copy Headers */,
5956B174200FF324008D9D16 /* RCTSinglelineTextInputView.h in Copy Headers */,
5956B175200FF324008D9D16 /* RCTSinglelineTextInputViewManager.h in Copy Headers */,
5956B176200FF324008D9D16 /* RCTUITextField.h in Copy Headers */,
5956B177200FF324008D9D16 /* RCTVirtualTextShadowView.h in Copy Headers */,
5956B178200FF324008D9D16 /* RCTVirtualTextViewManager.h in Copy Headers */,
);
name = "Copy Headers";
runOnlyForDeploymentPostprocessing = 0;
};
599DF2601F0306AD0079B53E /* Copy Headers */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = include/RCTText;
dstSubfolderSpec = 16;
files = (
5956B179200FF338008D9D16 /* RCTBaseTextShadowView.h in Copy Headers */,
5956B17A200FF338008D9D16 /* RCTBaseTextViewManager.h in Copy Headers */,
5956B17B200FF338008D9D16 /* RCTRawTextShadowView.h in Copy Headers */,
5956B17C200FF338008D9D16 /* RCTRawTextViewManager.h in Copy Headers */,
5956B17D200FF338008D9D16 /* RCTConvert+Text.h in Copy Headers */,
5956B17E200FF338008D9D16 /* RCTTextAttributes.h in Copy Headers */,
5956B17F200FF338008D9D16 /* NSTextStorage+FontScaling.h in Copy Headers */,
5956B180200FF338008D9D16 /* RCTTextShadowView.h in Copy Headers */,
5956B181200FF338008D9D16 /* RCTTextView.h in Copy Headers */,
5956B182200FF338008D9D16 /* RCTTextViewManager.h in Copy Headers */,
5956B183200FF338008D9D16 /* RCTMultilineTextInputView.h in Copy Headers */,
5956B184200FF338008D9D16 /* RCTMultilineTextInputViewManager.h in Copy Headers */,
5956B185200FF338008D9D16 /* RCTUITextView.h in Copy Headers */,
5956B186200FF338008D9D16 /* RCTBackedTextInputDelegate.h in Copy Headers */,
5956B187200FF338008D9D16 /* RCTBackedTextInputDelegateAdapter.h in Copy Headers */,
5956B188200FF338008D9D16 /* RCTBackedTextInputViewProtocol.h in Copy Headers */,
5956B189200FF338008D9D16 /* RCTBaseTextInputShadowView.h in Copy Headers */,
5956B18A200FF338008D9D16 /* RCTBaseTextInputView.h in Copy Headers */,
5956B18B200FF338008D9D16 /* RCTBaseTextInputViewManager.h in Copy Headers */,
5956B18C200FF338008D9D16 /* RCTTextSelection.h in Copy Headers */,
5956B18D200FF338008D9D16 /* RCTSinglelineTextInputView.h in Copy Headers */,
5956B18E200FF338008D9D16 /* RCTSinglelineTextInputViewManager.h in Copy Headers */,
5956B18F200FF338008D9D16 /* RCTUITextField.h in Copy Headers */,
5956B190200FF338008D9D16 /* RCTVirtualTextShadowView.h in Copy Headers */,
5956B191200FF338008D9D16 /* RCTVirtualTextViewManager.h in Copy Headers */,
);
name = "Copy Headers";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
2D2A287B1D9B048500D4039D /* libRCTText-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTText-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
58B5119B1A9E6C1200147676 /* libRCTText.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTText.a; sourceTree = BUILT_PRODUCTS_DIR; };
5956B0F9200FEBA9008D9D16 /* RCTConvert+Text.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+Text.h"; sourceTree = "<group>"; };
5956B0FB200FEBA9008D9D16 /* RCTRawTextViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRawTextViewManager.h; sourceTree = "<group>"; };
5956B0FC200FEBA9008D9D16 /* RCTRawTextShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRawTextShadowView.h; sourceTree = "<group>"; };
5956B0FD200FEBA9008D9D16 /* RCTRawTextShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRawTextShadowView.m; sourceTree = "<group>"; };
5956B0FE200FEBA9008D9D16 /* RCTRawTextViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRawTextViewManager.m; sourceTree = "<group>"; };
5956B101200FEBA9008D9D16 /* RCTSinglelineTextInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSinglelineTextInputView.m; sourceTree = "<group>"; };
5956B102200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSinglelineTextInputViewManager.h; sourceTree = "<group>"; };
5956B103200FEBA9008D9D16 /* RCTUITextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUITextField.m; sourceTree = "<group>"; };
5956B104200FEBA9008D9D16 /* RCTSinglelineTextInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSinglelineTextInputView.h; sourceTree = "<group>"; };
5956B105200FEBA9008D9D16 /* RCTUITextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTUITextField.h; sourceTree = "<group>"; };
5956B106200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSinglelineTextInputViewManager.m; sourceTree = "<group>"; };
5956B107200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBackedTextInputDelegateAdapter.h; sourceTree = "<group>"; };
5956B108200FEBA9008D9D16 /* RCTTextSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextSelection.h; sourceTree = "<group>"; };
5956B109200FEBA9008D9D16 /* RCTBaseTextInputShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBaseTextInputShadowView.h; sourceTree = "<group>"; };
5956B10A200FEBA9008D9D16 /* RCTBaseTextInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBaseTextInputView.m; sourceTree = "<group>"; };
5956B10B200FEBA9008D9D16 /* RCTBaseTextInputViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBaseTextInputViewManager.h; sourceTree = "<group>"; };
5956B10C200FEBA9008D9D16 /* RCTBackedTextInputDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBackedTextInputDelegate.h; sourceTree = "<group>"; };
5956B10D200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBackedTextInputDelegateAdapter.m; sourceTree = "<group>"; };
5956B10E200FEBA9008D9D16 /* RCTBaseTextInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBaseTextInputView.h; sourceTree = "<group>"; };
5956B10F200FEBA9008D9D16 /* RCTBaseTextInputShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBaseTextInputShadowView.m; sourceTree = "<group>"; };
5956B110200FEBA9008D9D16 /* RCTTextSelection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextSelection.m; sourceTree = "<group>"; };
5956B111200FEBA9008D9D16 /* RCTBaseTextInputViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBaseTextInputViewManager.m; sourceTree = "<group>"; };
5956B112200FEBA9008D9D16 /* RCTBackedTextInputViewProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBackedTextInputViewProtocol.h; sourceTree = "<group>"; };
5956B114200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMultilineTextInputViewManager.h; sourceTree = "<group>"; };
5956B115200FEBA9008D9D16 /* RCTMultilineTextInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMultilineTextInputView.m; sourceTree = "<group>"; };
5956B116200FEBA9008D9D16 /* RCTUITextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTUITextView.h; sourceTree = "<group>"; };
5956B117200FEBA9008D9D16 /* RCTMultilineTextInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMultilineTextInputView.h; sourceTree = "<group>"; };
5956B118200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMultilineTextInputViewManager.m; sourceTree = "<group>"; };
5956B119200FEBA9008D9D16 /* RCTUITextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUITextView.m; sourceTree = "<group>"; };
5956B11A200FEBA9008D9D16 /* RCTTextAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextAttributes.h; sourceTree = "<group>"; };
5956B11C200FEBA9008D9D16 /* RCTBaseTextViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBaseTextViewManager.h; sourceTree = "<group>"; };
5956B11D200FEBA9008D9D16 /* RCTBaseTextShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBaseTextShadowView.h; sourceTree = "<group>"; };
5956B11E200FEBA9008D9D16 /* RCTBaseTextShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBaseTextShadowView.m; sourceTree = "<group>"; };
5956B11F200FEBA9008D9D16 /* RCTBaseTextViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBaseTextViewManager.m; sourceTree = "<group>"; };
5956B120200FEBA9008D9D16 /* RCTTextAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextAttributes.m; sourceTree = "<group>"; };
5956B122200FEBAA008D9D16 /* RCTTextShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextShadowView.m; sourceTree = "<group>"; };
5956B123200FEBAA008D9D16 /* RCTTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextView.h; sourceTree = "<group>"; };
5956B124200FEBAA008D9D16 /* RCTTextViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextViewManager.h; sourceTree = "<group>"; };
5956B125200FEBAA008D9D16 /* NSTextStorage+FontScaling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTextStorage+FontScaling.m"; sourceTree = "<group>"; };
5956B126200FEBAA008D9D16 /* RCTTextShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextShadowView.h; sourceTree = "<group>"; };
5956B127200FEBAA008D9D16 /* RCTTextViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextViewManager.m; sourceTree = "<group>"; };
5956B128200FEBAA008D9D16 /* RCTTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextView.m; sourceTree = "<group>"; };
5956B129200FEBAA008D9D16 /* NSTextStorage+FontScaling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTextStorage+FontScaling.h"; sourceTree = "<group>"; };
5956B12B200FEBAA008D9D16 /* RCTVirtualTextViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVirtualTextViewManager.m; sourceTree = "<group>"; };
5956B12C200FEBAA008D9D16 /* RCTVirtualTextShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVirtualTextShadowView.h; sourceTree = "<group>"; };
5956B12D200FEBAA008D9D16 /* RCTVirtualTextViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVirtualTextViewManager.h; sourceTree = "<group>"; };
5956B12E200FEBAA008D9D16 /* RCTVirtualTextShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVirtualTextShadowView.m; sourceTree = "<group>"; };
5956B12F200FEBAA008D9D16 /* RCTConvert+Text.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+Text.m"; sourceTree = "<group>"; };
8F2807C1202D2B6A005D65E6 /* RCTInputAccessoryViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTInputAccessoryViewManager.m; sourceTree = "<group>"; };
8F2807C2202D2B6A005D65E6 /* RCTInputAccessoryViewContent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTInputAccessoryViewContent.h; sourceTree = "<group>"; };
8F2807C3202D2B6A005D65E6 /* RCTInputAccessoryView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTInputAccessoryView.m; sourceTree = "<group>"; };
8F2807C4202D2B6A005D65E6 /* RCTInputAccessoryView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTInputAccessoryView.h; sourceTree = "<group>"; };
8F2807C5202D2B6B005D65E6 /* RCTInputAccessoryViewContent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTInputAccessoryViewContent.m; sourceTree = "<group>"; };
8F2807C6202D2B6B005D65E6 /* RCTInputAccessoryViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTInputAccessoryViewManager.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
58B511921A9E6C1200147676 = {
isa = PBXGroup;
children = (
5956B11B200FEBA9008D9D16 /* BaseText */,
58B5119C1A9E6C1200147676 /* Products */,
5956B0FA200FEBA9008D9D16 /* RawText */,
5956B0F9200FEBA9008D9D16 /* RCTConvert+Text.h */,
5956B12F200FEBAA008D9D16 /* RCTConvert+Text.m */,
5956B11A200FEBA9008D9D16 /* RCTTextAttributes.h */,
5956B120200FEBA9008D9D16 /* RCTTextAttributes.m */,
5956B121200FEBAA008D9D16 /* Text */,
5956B0FF200FEBA9008D9D16 /* TextInput */,
5956B12A200FEBAA008D9D16 /* VirtualText */,
);
indentWidth = 2;
sourceTree = "<group>";
tabWidth = 2;
usesTabs = 0;
};
58B5119C1A9E6C1200147676 /* Products */ = {
isa = PBXGroup;
children = (
58B5119B1A9E6C1200147676 /* libRCTText.a */,
2D2A287B1D9B048500D4039D /* libRCTText-tvOS.a */,
);
name = Products;
sourceTree = "<group>";
};
5956B0FA200FEBA9008D9D16 /* RawText */ = {
isa = PBXGroup;
children = (
5956B0FC200FEBA9008D9D16 /* RCTRawTextShadowView.h */,
5956B0FD200FEBA9008D9D16 /* RCTRawTextShadowView.m */,
5956B0FB200FEBA9008D9D16 /* RCTRawTextViewManager.h */,
5956B0FE200FEBA9008D9D16 /* RCTRawTextViewManager.m */,
);
path = RawText;
sourceTree = "<group>";
};
5956B0FF200FEBA9008D9D16 /* TextInput */ = {
isa = PBXGroup;
children = (
8F2807C4202D2B6A005D65E6 /* RCTInputAccessoryView.h */,
8F2807C3202D2B6A005D65E6 /* RCTInputAccessoryView.m */,
8F2807C2202D2B6A005D65E6 /* RCTInputAccessoryViewContent.h */,
8F2807C5202D2B6B005D65E6 /* RCTInputAccessoryViewContent.m */,
8F2807C6202D2B6B005D65E6 /* RCTInputAccessoryViewManager.h */,
8F2807C1202D2B6A005D65E6 /* RCTInputAccessoryViewManager.m */,
5956B113200FEBA9008D9D16 /* Multiline */,
5956B10C200FEBA9008D9D16 /* RCTBackedTextInputDelegate.h */,
5956B107200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.h */,
5956B10D200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.m */,
5956B112200FEBA9008D9D16 /* RCTBackedTextInputViewProtocol.h */,
5956B109200FEBA9008D9D16 /* RCTBaseTextInputShadowView.h */,
5956B10F200FEBA9008D9D16 /* RCTBaseTextInputShadowView.m */,
5956B10E200FEBA9008D9D16 /* RCTBaseTextInputView.h */,
5956B10A200FEBA9008D9D16 /* RCTBaseTextInputView.m */,
5956B10B200FEBA9008D9D16 /* RCTBaseTextInputViewManager.h */,
5956B111200FEBA9008D9D16 /* RCTBaseTextInputViewManager.m */,
5956B108200FEBA9008D9D16 /* RCTTextSelection.h */,
5956B110200FEBA9008D9D16 /* RCTTextSelection.m */,
5956B100200FEBA9008D9D16 /* Singleline */,
);
path = TextInput;
sourceTree = "<group>";
};
5956B100200FEBA9008D9D16 /* Singleline */ = {
isa = PBXGroup;
children = (
5956B104200FEBA9008D9D16 /* RCTSinglelineTextInputView.h */,
5956B101200FEBA9008D9D16 /* RCTSinglelineTextInputView.m */,
5956B102200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.h */,
5956B106200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.m */,
5956B105200FEBA9008D9D16 /* RCTUITextField.h */,
5956B103200FEBA9008D9D16 /* RCTUITextField.m */,
);
path = Singleline;
sourceTree = "<group>";
};
5956B113200FEBA9008D9D16 /* Multiline */ = {
isa = PBXGroup;
children = (
5956B117200FEBA9008D9D16 /* RCTMultilineTextInputView.h */,
5956B115200FEBA9008D9D16 /* RCTMultilineTextInputView.m */,
5956B114200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.h */,
5956B118200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.m */,
5956B116200FEBA9008D9D16 /* RCTUITextView.h */,
5956B119200FEBA9008D9D16 /* RCTUITextView.m */,
);
path = Multiline;
sourceTree = "<group>";
};
5956B11B200FEBA9008D9D16 /* BaseText */ = {
isa = PBXGroup;
children = (
5956B11D200FEBA9008D9D16 /* RCTBaseTextShadowView.h */,
5956B11E200FEBA9008D9D16 /* RCTBaseTextShadowView.m */,
5956B11C200FEBA9008D9D16 /* RCTBaseTextViewManager.h */,
5956B11F200FEBA9008D9D16 /* RCTBaseTextViewManager.m */,
);
path = BaseText;
sourceTree = "<group>";
};
5956B121200FEBAA008D9D16 /* Text */ = {
isa = PBXGroup;
children = (
5956B129200FEBAA008D9D16 /* NSTextStorage+FontScaling.h */,
5956B125200FEBAA008D9D16 /* NSTextStorage+FontScaling.m */,
5956B126200FEBAA008D9D16 /* RCTTextShadowView.h */,
5956B122200FEBAA008D9D16 /* RCTTextShadowView.m */,
5956B123200FEBAA008D9D16 /* RCTTextView.h */,
5956B128200FEBAA008D9D16 /* RCTTextView.m */,
5956B124200FEBAA008D9D16 /* RCTTextViewManager.h */,
5956B127200FEBAA008D9D16 /* RCTTextViewManager.m */,
);
path = Text;
sourceTree = "<group>";
};
5956B12A200FEBAA008D9D16 /* VirtualText */ = {
isa = PBXGroup;
children = (
5956B12C200FEBAA008D9D16 /* RCTVirtualTextShadowView.h */,
5956B12E200FEBAA008D9D16 /* RCTVirtualTextShadowView.m */,
5956B12D200FEBAA008D9D16 /* RCTVirtualTextViewManager.h */,
5956B12B200FEBAA008D9D16 /* RCTVirtualTextViewManager.m */,
);
path = VirtualText;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
2D2A287A1D9B048500D4039D /* RCTText-tvOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = 2D2A28831D9B048500D4039D /* Build configuration list for PBXNativeTarget "RCTText-tvOS" */;
buildPhases = (
599DF2601F0306AD0079B53E /* Copy Headers */,
2D2A28771D9B048500D4039D /* Sources */,
);
buildRules = (
);
dependencies = (
);
name = "RCTText-tvOS";
productName = "RCTText-tvOS";
productReference = 2D2A287B1D9B048500D4039D /* libRCTText-tvOS.a */;
productType = "com.apple.product-type.library.static";
};
58B5119A1A9E6C1200147676 /* RCTText */ = {
isa = PBXNativeTarget;
buildConfigurationList = 58B511AF1A9E6C1300147676 /* Build configuration list for PBXNativeTarget "RCTText" */;
buildPhases = (
599DF25E1F0306540079B53E /* Copy Headers */,
58B511971A9E6C1200147676 /* Sources */,
);
buildRules = (
);
dependencies = (
);
name = RCTText;
productName = RCTText;
productReference = 58B5119B1A9E6C1200147676 /* libRCTText.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
58B511931A9E6C1200147676 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
2D2A287A1D9B048500D4039D = {
CreatedOnToolsVersion = 8.0;
ProvisioningStyle = Automatic;
};
58B5119A1A9E6C1200147676 = {
CreatedOnToolsVersion = 6.1.1;
};
};
};
buildConfigurationList = 58B511961A9E6C1200147676 /* Build configuration list for PBXProject "RCTText" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 58B511921A9E6C1200147676;
productRefGroup = 58B5119C1A9E6C1200147676 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
58B5119A1A9E6C1200147676 /* RCTText */,
2D2A287A1D9B048500D4039D /* RCTText-tvOS */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
2D2A28771D9B048500D4039D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5956B192200FF35C008D9D16 /* RCTBaseTextShadowView.m in Sources */,
5956B193200FF35C008D9D16 /* RCTBaseTextViewManager.m in Sources */,
5956B194200FF35C008D9D16 /* RCTRawTextShadowView.m in Sources */,
5956B195200FF35C008D9D16 /* RCTRawTextViewManager.m in Sources */,
5956B196200FF35C008D9D16 /* RCTConvert+Text.m in Sources */,
5956B197200FF35C008D9D16 /* RCTTextAttributes.m in Sources */,
5956B198200FF35C008D9D16 /* NSTextStorage+FontScaling.m in Sources */,
5956B199200FF35C008D9D16 /* RCTTextShadowView.m in Sources */,
5956B19A200FF35C008D9D16 /* RCTTextView.m in Sources */,
5956B19B200FF35C008D9D16 /* RCTTextViewManager.m in Sources */,
5956B19C200FF35C008D9D16 /* RCTMultilineTextInputView.m in Sources */,
5956B19D200FF35C008D9D16 /* RCTMultilineTextInputViewManager.m in Sources */,
5956B19E200FF35C008D9D16 /* RCTUITextView.m in Sources */,
5956B19F200FF35C008D9D16 /* RCTBackedTextInputDelegateAdapter.m in Sources */,
5956B1A0200FF35C008D9D16 /* RCTBaseTextInputShadowView.m in Sources */,
5956B1A1200FF35C008D9D16 /* RCTBaseTextInputView.m in Sources */,
5956B1A2200FF35C008D9D16 /* RCTBaseTextInputViewManager.m in Sources */,
5956B1A3200FF35C008D9D16 /* RCTTextSelection.m in Sources */,
5956B1A4200FF35C008D9D16 /* RCTSinglelineTextInputView.m in Sources */,
5956B1A5200FF35C008D9D16 /* RCTSinglelineTextInputViewManager.m in Sources */,
5956B1A6200FF35C008D9D16 /* RCTUITextField.m in Sources */,
5956B1A7200FF35C008D9D16 /* RCTVirtualTextShadowView.m in Sources */,
5956B1A8200FF35C008D9D16 /* RCTVirtualTextViewManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
58B511971A9E6C1200147676 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5956B13D200FEBAA008D9D16 /* RCTBaseTextShadowView.m in Sources */,
5956B140200FEBAA008D9D16 /* RCTTextShadowView.m in Sources */,
5956B131200FEBAA008D9D16 /* RCTRawTextViewManager.m in Sources */,
5956B137200FEBAA008D9D16 /* RCTBaseTextInputShadowView.m in Sources */,
8F2807C7202D2B6B005D65E6 /* RCTInputAccessoryViewManager.m in Sources */,
5956B146200FEBAA008D9D16 /* RCTConvert+Text.m in Sources */,
8F2807C9202D2B6B005D65E6 /* RCTInputAccessoryViewContent.m in Sources */,
5956B13F200FEBAA008D9D16 /* RCTTextAttributes.m in Sources */,
8F2807C8202D2B6B005D65E6 /* RCTInputAccessoryView.m in Sources */,
5956B143200FEBAA008D9D16 /* RCTTextView.m in Sources */,
5956B13C200FEBAA008D9D16 /* RCTUITextView.m in Sources */,
5956B136200FEBAA008D9D16 /* RCTBackedTextInputDelegateAdapter.m in Sources */,
5956B13E200FEBAA008D9D16 /* RCTBaseTextViewManager.m in Sources */,
5956B145200FEBAA008D9D16 /* RCTVirtualTextShadowView.m in Sources */,
5956B142200FEBAA008D9D16 /* RCTTextViewManager.m in Sources */,
5956B135200FEBAA008D9D16 /* RCTBaseTextInputView.m in Sources */,
5956B144200FEBAA008D9D16 /* RCTVirtualTextViewManager.m in Sources */,
5956B13B200FEBAA008D9D16 /* RCTMultilineTextInputViewManager.m in Sources */,
5956B134200FEBAA008D9D16 /* RCTSinglelineTextInputViewManager.m in Sources */,
5956B139200FEBAA008D9D16 /* RCTBaseTextInputViewManager.m in Sources */,
5956B138200FEBAA008D9D16 /* RCTTextSelection.m in Sources */,
5956B130200FEBAA008D9D16 /* RCTRawTextShadowView.m in Sources */,
5956B141200FEBAA008D9D16 /* NSTextStorage+FontScaling.m in Sources */,
5956B132200FEBAA008D9D16 /* RCTSinglelineTextInputView.m in Sources */,
5956B13A200FEBAA008D9D16 /* RCTMultilineTextInputView.m in Sources */,
5956B133200FEBAA008D9D16 /* RCTUITextField.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
2D2A28811D9B048500D4039D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
TVOS_DEPLOYMENT_TARGET = 9.2;
};
name = Debug;
};
2D2A28821D9B048500D4039D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_NO_COMMON_BLOCKS = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
TVOS_DEPLOYMENT_TARGET = 9.2;
};
name = Release;
};
58B511AD1A9E6C1300147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
WARNING_CFLAGS = (
"-Werror",
"-Wall",
);
};
name = Debug;
};
58B511AE1A9E6C1300147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
VALIDATE_PRODUCT = YES;
WARNING_CFLAGS = (
"-Werror",
"-Wall",
);
};
name = Release;
};
58B511B01A9E6C1300147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_STATIC_ANALYZER_MODE = deep;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
RUN_CLANG_STATIC_ANALYZER = YES;
};
name = Debug;
};
58B511B11A9E6C1300147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_STATIC_ANALYZER_MODE = deep;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
2D2A28831D9B048500D4039D /* Build configuration list for PBXNativeTarget "RCTText-tvOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2D2A28811D9B048500D4039D /* Debug */,
2D2A28821D9B048500D4039D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
58B511961A9E6C1200147676 /* Build configuration list for PBXProject "RCTText" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511AD1A9E6C1300147676 /* Debug */,
58B511AE1A9E6C1300147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
58B511AF1A9E6C1300147676 /* Build configuration list for PBXNativeTarget "RCTText" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511B01A9E6C1300147676 /* Debug */,
58B511B11A9E6C1300147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 58B511931A9E6C1200147676 /* Project object */;
}

View File

@@ -0,0 +1,83 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTTextDecorationLineType.h>
NS_ASSUME_NONNULL_BEGIN
extern NSString *const RCTTextAttributesIsHighlightedAttributeName;
extern NSString *const RCTTextAttributesTagAttributeName;
/**
* Represents knowledge about all supported *text* attributes
* assigned to some text component such as <Text>, <VirtualText>,
* and <TextInput>.
*/
@interface RCTTextAttributes : NSObject <NSCopying>
// Color
@property (nonatomic, strong, nullable) UIColor *foregroundColor;
@property (nonatomic, strong, nullable) UIColor *backgroundColor;
@property (nonatomic, assign) CGFloat opacity;
// Font
@property (nonatomic, copy, nullable) NSString *fontFamily;
@property (nonatomic, assign) CGFloat fontSize;
@property (nonatomic, assign) CGFloat fontSizeMultiplier;
@property (nonatomic, copy, nullable) NSString *fontWeight;
@property (nonatomic, copy, nullable) NSString *fontStyle;
@property (nonatomic, copy, nullable) NSArray<NSString *> *fontVariant;
@property (nonatomic, assign) BOOL allowFontScaling;
@property (nonatomic, assign) CGFloat letterSpacing;
// Paragraph Styles
@property (nonatomic, assign) CGFloat lineHeight;
@property (nonatomic, assign) NSTextAlignment alignment;
@property (nonatomic, assign) NSWritingDirection baseWritingDirection;
// Decoration
@property (nonatomic, strong, nullable) UIColor *textDecorationColor;
@property (nonatomic, assign) NSUnderlineStyle textDecorationStyle;
@property (nonatomic, assign) RCTTextDecorationLineType textDecorationLine;
// Shadow
@property (nonatomic, assign) CGSize textShadowOffset;
@property (nonatomic, assign) CGFloat textShadowRadius;
@property (nonatomic, strong, nullable) UIColor *textShadowColor;
// Special
@property (nonatomic, assign) BOOL isHighlighted;
@property (nonatomic, strong, nullable) NSNumber *tag;
@property (nonatomic, assign) UIUserInterfaceLayoutDirection layoutDirection;
#pragma mark - Inheritance
- (void)applyTextAttributes:(RCTTextAttributes *)textAttributes;
#pragma mark - Adapters
/**
* Text attributes in NSAttributedString terms.
*/
- (NSDictionary<NSAttributedStringKey, id> *)effectiveTextAttributes;
/**
* Constructed font.
*/
- (UIFont *)effectiveFont;
/**
* Font size multiplier reflects `allowFontScaling` and `fontSizeMultiplier`.
*/
- (CGFloat)effectiveFontSizeMultiplier;
/**
* Foreground and background colors with opacity and right defaults.
*/
- (UIColor *)effectiveForegroundColor;
- (UIColor *)effectiveBackgroundColor;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,268 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTTextAttributes.h"
#import <React/RCTAssert.h>
#import <React/RCTFont.h>
#import <React/RCTLog.h>
NSString *const RCTTextAttributesIsHighlightedAttributeName = @"RCTTextAttributesIsHighlightedAttributeName";
NSString *const RCTTextAttributesTagAttributeName = @"RCTTextAttributesTagAttributeName";
@implementation RCTTextAttributes
- (instancetype)init
{
if (self = [super init]) {
_fontSize = NAN;
_letterSpacing = NAN;
_textDecorationStyle = NSUnderlineStyleSingle;
_fontSizeMultiplier = NAN;
_alignment = NSTextAlignmentNatural;
_baseWritingDirection = NSWritingDirectionNatural;
_textShadowRadius = NAN;
_opacity = NAN;
}
return self;
}
- (void)applyTextAttributes:(RCTTextAttributes *)textAttributes
{
// Note: All lines marked with `*` does not use explicit/correct rules to compare old and new values becuase
// their types do not have special designated value representing undefined/unspecified/inherit meaning.
// We will address this in the future.
// Color
_foregroundColor = textAttributes->_foregroundColor ?: _foregroundColor;
_backgroundColor = textAttributes->_backgroundColor ?: _backgroundColor;
_opacity = !isnan(textAttributes->_opacity) ? (isnan(_opacity) ? 1.0 : _opacity) * textAttributes->_opacity : _opacity;
// Font
_fontFamily = textAttributes->_fontFamily ?: _fontFamily;
_fontSize = !isnan(textAttributes->_fontSize) ? textAttributes->_fontSize : _fontSize;
_fontSizeMultiplier = !isnan(textAttributes->_fontSizeMultiplier) ? textAttributes->_fontSizeMultiplier : _fontSizeMultiplier;
_fontWeight = textAttributes->_fontWeight ?: _fontWeight;
_fontStyle = textAttributes->_fontStyle ?: _fontStyle;
_fontVariant = textAttributes->_fontVariant ?: _fontVariant;
_allowFontScaling = textAttributes->_allowFontScaling || _allowFontScaling; // *
_letterSpacing = !isnan(textAttributes->_letterSpacing) ? textAttributes->_letterSpacing : _letterSpacing;
// Paragraph Styles
_lineHeight = !isnan(textAttributes->_lineHeight) ? textAttributes->_lineHeight : _lineHeight;
_alignment = textAttributes->_alignment != NSTextAlignmentNatural ? textAttributes->_alignment : _alignment; // *
_baseWritingDirection = textAttributes->_baseWritingDirection != NSWritingDirectionNatural ? textAttributes->_baseWritingDirection : _baseWritingDirection; // *
// Decoration
_textDecorationColor = textAttributes->_textDecorationColor ?: _textDecorationColor;
_textDecorationStyle = textAttributes->_textDecorationStyle != NSUnderlineStyleSingle ? textAttributes->_textDecorationStyle : _textDecorationStyle; // *
_textDecorationLine = textAttributes->_textDecorationLine != RCTTextDecorationLineTypeNone ? textAttributes->_textDecorationLine : _textDecorationLine; // *
// Shadow
_textShadowOffset = !CGSizeEqualToSize(textAttributes->_textShadowOffset, CGSizeZero) ? textAttributes->_textShadowOffset : _textShadowOffset; // *
_textShadowRadius = !isnan(textAttributes->_textShadowRadius) ? textAttributes->_textShadowRadius : _textShadowRadius;
_textShadowColor = textAttributes->_textShadowColor ?: _textShadowColor;
// Special
_isHighlighted = textAttributes->_isHighlighted || _isHighlighted; // *
_tag = textAttributes->_tag ?: _tag;
_layoutDirection = textAttributes->_layoutDirection != UIUserInterfaceLayoutDirectionLeftToRight ? textAttributes->_layoutDirection : _layoutDirection;
}
- (NSDictionary<NSAttributedStringKey, id> *)effectiveTextAttributes
{
NSMutableDictionary<NSAttributedStringKey, id> *attributes =
[NSMutableDictionary dictionaryWithCapacity:10];
// Font
UIFont *font = self.effectiveFont;
if (font) {
attributes[NSFontAttributeName] = font;
}
// Colors
UIColor *effectiveForegroundColor = self.effectiveForegroundColor;
if (_foregroundColor || !isnan(_opacity)) {
attributes[NSForegroundColorAttributeName] = effectiveForegroundColor;
}
if (_backgroundColor || !isnan(_opacity)) {
attributes[NSBackgroundColorAttributeName] = self.effectiveBackgroundColor;
}
// Kerning
if (!isnan(_letterSpacing)) {
attributes[NSKernAttributeName] = @(_letterSpacing);
}
// Paragraph Style
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
BOOL isParagraphStyleUsed = NO;
if (_alignment != NSTextAlignmentNatural) {
NSTextAlignment alignment = _alignment;
if (_layoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
if (alignment == NSTextAlignmentRight) {
alignment = NSTextAlignmentLeft;
} else if (alignment == NSTextAlignmentLeft) {
alignment = NSTextAlignmentRight;
}
}
paragraphStyle.alignment = alignment;
isParagraphStyleUsed = YES;
}
if (_baseWritingDirection != NSWritingDirectionNatural) {
paragraphStyle.baseWritingDirection = _baseWritingDirection;
isParagraphStyleUsed = YES;
}
if (!isnan(_lineHeight)) {
CGFloat lineHeight = _lineHeight * self.effectiveFontSizeMultiplier;
paragraphStyle.minimumLineHeight = lineHeight;
paragraphStyle.maximumLineHeight = lineHeight;
isParagraphStyleUsed = YES;
}
if (isParagraphStyleUsed) {
attributes[NSParagraphStyleAttributeName] = paragraphStyle;
}
// Decoration
BOOL isTextDecorationEnabled = NO;
if (_textDecorationLine == RCTTextDecorationLineTypeUnderline ||
_textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough) {
isTextDecorationEnabled = YES;
attributes[NSUnderlineStyleAttributeName] = @(_textDecorationStyle);
}
if (_textDecorationLine == RCTTextDecorationLineTypeStrikethrough ||
_textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough){
isTextDecorationEnabled = YES;
attributes[NSStrikethroughStyleAttributeName] = @(_textDecorationStyle);
}
if (_textDecorationColor || isTextDecorationEnabled) {
attributes[NSStrikethroughColorAttributeName] = _textDecorationColor ?: effectiveForegroundColor;
attributes[NSUnderlineColorAttributeName] = _textDecorationColor ?: effectiveForegroundColor;
}
// Shadow
if (!CGSizeEqualToSize(_textShadowOffset, CGSizeZero)) {
NSShadow *shadow = [NSShadow new];
shadow.shadowOffset = _textShadowOffset;
shadow.shadowBlurRadius = _textShadowRadius;
shadow.shadowColor = _textShadowColor;
attributes[NSShadowAttributeName] = shadow;
}
// Special
if (_isHighlighted) {
attributes[RCTTextAttributesIsHighlightedAttributeName] = @YES;
}
if (_tag) {
attributes[RCTTextAttributesTagAttributeName] = _tag;
}
return [attributes copy];
}
- (UIFont *)effectiveFont
{
// FIXME: RCTFont has thread-safety issues and must be rewritten.
return [RCTFont updateFont:nil
withFamily:_fontFamily
size:@(isnan(_fontSize) ? 0 : _fontSize)
weight:_fontWeight
style:_fontStyle
variant:_fontVariant
scaleMultiplier:self.effectiveFontSizeMultiplier];
}
- (CGFloat)effectiveFontSizeMultiplier
{
return !RCTHasFontHandlerSet() && _allowFontScaling && !isnan(_fontSizeMultiplier) ? _fontSizeMultiplier : 1.0;
}
- (UIColor *)effectiveForegroundColor
{
UIColor *effectiveForegroundColor = _foregroundColor ?: [UIColor blackColor];
if (!isnan(_opacity)) {
effectiveForegroundColor = [effectiveForegroundColor colorWithAlphaComponent:CGColorGetAlpha(effectiveForegroundColor.CGColor) * _opacity];
}
return effectiveForegroundColor;
}
- (UIColor *)effectiveBackgroundColor
{
UIColor *effectiveBackgroundColor = _backgroundColor;// ?: [[UIColor whiteColor] colorWithAlphaComponent:0];
if (effectiveBackgroundColor && !isnan(_opacity)) {
effectiveBackgroundColor = [effectiveBackgroundColor colorWithAlphaComponent:CGColorGetAlpha(effectiveBackgroundColor.CGColor) * _opacity];
}
return effectiveBackgroundColor ?: [UIColor clearColor];
}
- (RCTTextAttributes *)copyWithZone:(NSZone *)zone
{
RCTTextAttributes *textAttributes = [RCTTextAttributes new];
[textAttributes applyTextAttributes:self];
return textAttributes;
}
#pragma mark - NSObject
- (BOOL)isEqual:(RCTTextAttributes *)textAttributes
{
if (self == textAttributes) {
return YES;
}
#define RCTTextAttributesCompareFloats(a) ((a == textAttributes->a) || (isnan(a) && isnan(textAttributes->a)))
#define RCTTextAttributesCompareSize(a) CGSizeEqualToSize(a, textAttributes->a)
#define RCTTextAttributesCompareObjects(a) ((a == textAttributes->a) || [a isEqual:textAttributes->a])
#define RCTTextAttributesCompareStrings(a) ((a == textAttributes->a) || [a isEqualToString:textAttributes->a])
#define RCTTextAttributesCompareOthers(a) (a == textAttributes->a)
return
RCTTextAttributesCompareObjects(_foregroundColor) &&
RCTTextAttributesCompareObjects(_backgroundColor) &&
RCTTextAttributesCompareFloats(_opacity) &&
// Font
RCTTextAttributesCompareObjects(_fontFamily) &&
RCTTextAttributesCompareFloats(_fontSize) &&
RCTTextAttributesCompareFloats(_fontSizeMultiplier) &&
RCTTextAttributesCompareStrings(_fontWeight) &&
RCTTextAttributesCompareObjects(_fontStyle) &&
RCTTextAttributesCompareObjects(_fontVariant) &&
RCTTextAttributesCompareOthers(_allowFontScaling) &&
RCTTextAttributesCompareFloats(_letterSpacing) &&
// Paragraph Styles
RCTTextAttributesCompareFloats(_lineHeight) &&
RCTTextAttributesCompareFloats(_alignment) &&
RCTTextAttributesCompareOthers(_baseWritingDirection) &&
// Decoration
RCTTextAttributesCompareObjects(_textDecorationColor) &&
RCTTextAttributesCompareOthers(_textDecorationStyle) &&
RCTTextAttributesCompareOthers(_textDecorationLine) &&
// Shadow
RCTTextAttributesCompareSize(_textShadowOffset) &&
RCTTextAttributesCompareFloats(_textShadowRadius) &&
RCTTextAttributesCompareObjects(_textShadowColor) &&
// Special
RCTTextAttributesCompareOthers(_isHighlighted) &&
RCTTextAttributesCompareObjects(_tag) &&
RCTTextAttributesCompareOthers(_layoutDirection);
}
@end

View File

@@ -0,0 +1,18 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTShadowView.h>
NS_ASSUME_NONNULL_BEGIN
@interface RCTRawTextShadowView : RCTShadowView
@property (nonatomic, copy, nullable) NSString *text;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTRawTextShadowView.h"
#import <React/RCTShadowView+Layout.h>
@implementation RCTRawTextShadowView
- (void)setText:(NSString *)text
{
if (_text != text && ![_text isEqualToString:text]) {
_text = [text copy];
[self dirtyLayout];
}
}
- (void)dirtyLayout
{
[self.superview dirtyLayout];
}
- (NSString *)description
{
NSString *superDescription = super.description;
return [[superDescription substringToIndex:superDescription.length - 1] stringByAppendingFormat:@"; text: %@>", self.text];
}
@end

View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTViewManager.h>
NS_ASSUME_NONNULL_BEGIN
@interface RCTRawTextViewManager : RCTViewManager
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTRawTextViewManager.h"
#import "RCTRawTextShadowView.h"
@implementation RCTRawTextViewManager
RCT_EXPORT_MODULE(RCTRawText)
- (UIView *)view
{
return [UIView new];
}
- (RCTShadowView *)shadowView
{
return [RCTRawTextShadowView new];
}
RCT_EXPORT_SHADOW_PROPERTY(text, NSString)
@end

231
node_modules/react-native/Libraries/Text/Text.js generated vendored Normal file
View File

@@ -0,0 +1,231 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule Text
* @flow
* @format
*/
'use strict';
const NativeMethodsMixin = require('NativeMethodsMixin');
const React = require('React');
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
const TextPropTypes = require('TextPropTypes');
const Touchable = require('Touchable');
const UIManager = require('UIManager');
const createReactClass = require('create-react-class');
const createReactNativeComponentClass = require('createReactNativeComponentClass');
const mergeFast = require('mergeFast');
const processColor = require('processColor');
const {ViewContextTypes} = require('ViewContext');
const viewConfig = {
validAttributes: mergeFast(ReactNativeViewAttributes.UIView, {
isHighlighted: true,
numberOfLines: true,
ellipsizeMode: true,
allowFontScaling: true,
disabled: true,
selectable: true,
selectionColor: true,
adjustsFontSizeToFit: true,
minimumFontScale: true,
textBreakStrategy: true,
}),
uiViewClassName: 'RCTText',
};
import type {ViewChildContext} from 'ViewContext';
/**
* A React component for displaying text.
*
* See https://facebook.github.io/react-native/docs/text.html
*/
const Text = createReactClass({
displayName: 'Text',
propTypes: TextPropTypes,
getDefaultProps(): Object {
return {
accessible: true,
allowFontScaling: true,
ellipsizeMode: 'tail',
};
},
getInitialState: function(): Object {
return mergeFast(Touchable.Mixin.touchableGetInitialState(), {
isHighlighted: false,
});
},
mixins: [NativeMethodsMixin],
viewConfig: viewConfig,
getChildContext(): ViewChildContext {
return {
isInAParentText: true,
};
},
childContextTypes: ViewContextTypes,
contextTypes: ViewContextTypes,
/**
* Only assigned if touch is needed.
*/
_handlers: (null: ?Object),
_hasPressHandler(): boolean {
return !!this.props.onPress || !!this.props.onLongPress;
},
/**
* These are assigned lazily the first time the responder is set to make plain
* text nodes as cheap as possible.
*/
touchableHandleActivePressIn: (null: ?Function),
touchableHandleActivePressOut: (null: ?Function),
touchableHandlePress: (null: ?Function),
touchableHandleLongPress: (null: ?Function),
touchableGetPressRectOffset: (null: ?Function),
render(): React.Element<any> {
let newProps = this.props;
if (this.props.onStartShouldSetResponder || this._hasPressHandler()) {
if (!this._handlers) {
this._handlers = {
onStartShouldSetResponder: (): boolean => {
const shouldSetFromProps =
this.props.onStartShouldSetResponder &&
// $FlowFixMe(>=0.41.0)
this.props.onStartShouldSetResponder();
const setResponder = shouldSetFromProps || this._hasPressHandler();
if (setResponder && !this.touchableHandleActivePressIn) {
// Attach and bind all the other handlers only the first time a touch
// actually happens.
for (const key in Touchable.Mixin) {
if (typeof Touchable.Mixin[key] === 'function') {
(this: any)[key] = Touchable.Mixin[key].bind(this);
}
}
this.touchableHandleActivePressIn = () => {
if (
this.props.suppressHighlighting ||
!this._hasPressHandler()
) {
return;
}
this.setState({
isHighlighted: true,
});
};
this.touchableHandleActivePressOut = () => {
if (
this.props.suppressHighlighting ||
!this._hasPressHandler()
) {
return;
}
this.setState({
isHighlighted: false,
});
};
this.touchableHandlePress = (e: SyntheticEvent<>) => {
this.props.onPress && this.props.onPress(e);
};
this.touchableHandleLongPress = (e: SyntheticEvent<>) => {
this.props.onLongPress && this.props.onLongPress(e);
};
this.touchableGetPressRectOffset = function(): RectOffset {
return this.props.pressRetentionOffset || PRESS_RECT_OFFSET;
};
}
return setResponder;
},
onResponderGrant: function(e: SyntheticEvent<>, dispatchID: string) {
this.touchableHandleResponderGrant(e, dispatchID);
this.props.onResponderGrant &&
this.props.onResponderGrant.apply(this, arguments);
}.bind(this),
onResponderMove: function(e: SyntheticEvent<>) {
this.touchableHandleResponderMove(e);
this.props.onResponderMove &&
this.props.onResponderMove.apply(this, arguments);
}.bind(this),
onResponderRelease: function(e: SyntheticEvent<>) {
this.touchableHandleResponderRelease(e);
this.props.onResponderRelease &&
this.props.onResponderRelease.apply(this, arguments);
}.bind(this),
onResponderTerminate: function(e: SyntheticEvent<>) {
this.touchableHandleResponderTerminate(e);
this.props.onResponderTerminate &&
this.props.onResponderTerminate.apply(this, arguments);
}.bind(this),
onResponderTerminationRequest: function(): boolean {
// Allow touchable or props.onResponderTerminationRequest to deny
// the request
var allowTermination = this.touchableHandleResponderTerminationRequest();
if (allowTermination && this.props.onResponderTerminationRequest) {
allowTermination = this.props.onResponderTerminationRequest.apply(
this,
arguments,
);
}
return allowTermination;
}.bind(this),
};
}
newProps = {
...this.props,
...this._handlers,
isHighlighted: this.state.isHighlighted,
};
}
if (newProps.selectionColor != null) {
newProps = {
...newProps,
selectionColor: processColor(newProps.selectionColor),
};
}
if (Touchable.TOUCH_TARGET_DEBUG && newProps.onPress) {
newProps = {
...newProps,
style: [this.props.style, {color: 'magenta'}],
};
}
if (this.context.isInAParentText) {
return <RCTVirtualText {...newProps} />;
} else {
return <RCTText {...newProps} />;
}
},
});
type RectOffset = {
top: number,
left: number,
right: number,
bottom: number,
};
var PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
var RCTText = createReactNativeComponentClass(
viewConfig.uiViewClassName,
() => viewConfig,
);
var RCTVirtualText = RCTText;
if (UIManager.RCTVirtualText) {
RCTVirtualText = createReactNativeComponentClass('RCTVirtualText', () => ({
validAttributes: mergeFast(ReactNativeViewAttributes.UIView, {
isHighlighted: true,
}),
uiViewClassName: 'RCTVirtualText',
}));
}
module.exports = Text;

View File

@@ -0,0 +1,20 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
@interface NSTextStorage (FontScaling)
- (void)scaleFontSizeToFitSize:(CGSize)size
minimumFontSize:(CGFloat)minimumFontSize
maximumFontSize:(CGFloat)maximumFontSize;
- (void)scaleFontSizeWithRatio:(CGFloat)ratio
minimumFontSize:(CGFloat)minimumFontSize
maximumFontSize:(CGFloat)maximumFontSize;
@end

View File

@@ -0,0 +1,137 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "NSTextStorage+FontScaling.h"
typedef NS_OPTIONS(NSInteger, RCTTextSizeComparisonOptions) {
RCTTextSizeComparisonSmaller = 1 << 0,
RCTTextSizeComparisonLarger = 1 << 1,
RCTTextSizeComparisonWithinRange = 1 << 2,
};
@implementation NSTextStorage (FontScaling)
- (void)scaleFontSizeToFitSize:(CGSize)size
minimumFontSize:(CGFloat)minimumFontSize
maximumFontSize:(CGFloat)maximumFontSize
{
CGFloat bottomRatio = 1.0/128.0;
CGFloat topRatio = 128.0;
CGFloat ratio = 1.0;
NSAttributedString *originalAttributedString = [self copy];
CGFloat lastRatioWhichFits = 0.02;
while (true) {
[self scaleFontSizeWithRatio:ratio
minimumFontSize:minimumFontSize
maximumFontSize:maximumFontSize];
RCTTextSizeComparisonOptions comparsion =
[self compareToSize:size thresholdRatio:0.01];
if (
(comparsion & RCTTextSizeComparisonWithinRange) &&
(comparsion & RCTTextSizeComparisonSmaller)
) {
return;
} else if (comparsion & RCTTextSizeComparisonSmaller) {
bottomRatio = ratio;
lastRatioWhichFits = ratio;
} else {
topRatio = ratio;
}
ratio = (topRatio + bottomRatio) / 2.0;
CGFloat kRatioThreshold = 0.005;
if (
ABS(topRatio - bottomRatio) < kRatioThreshold ||
ABS(topRatio - ratio) < kRatioThreshold ||
ABS(bottomRatio - ratio) < kRatioThreshold
) {
[self replaceCharactersInRange:(NSRange){0, self.length}
withAttributedString:originalAttributedString];
[self scaleFontSizeWithRatio:lastRatioWhichFits
minimumFontSize:minimumFontSize
maximumFontSize:maximumFontSize];
return;
}
[self replaceCharactersInRange:(NSRange){0, self.length}
withAttributedString:originalAttributedString];
}
}
- (RCTTextSizeComparisonOptions)compareToSize:(CGSize)size thresholdRatio:(CGFloat)thresholdRatio
{
NSLayoutManager *layoutManager = self.layoutManagers.firstObject;
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
[layoutManager ensureLayoutForTextContainer:textContainer];
// Does it fit the text container?
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
NSRange truncatedGlyphRange = [layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:glyphRange.length - 1];
if (truncatedGlyphRange.location != NSNotFound) {
return RCTTextSizeComparisonLarger;
}
CGSize measuredSize = [layoutManager usedRectForTextContainer:textContainer].size;
// Does it fit the size?
BOOL fitsSize =
size.width >= measuredSize.width &&
size.height >= measuredSize.height;
CGSize thresholdSize = (CGSize){
size.width * thresholdRatio,
size.height * thresholdRatio,
};
RCTTextSizeComparisonOptions result = 0;
result |= (fitsSize) ? RCTTextSizeComparisonSmaller : RCTTextSizeComparisonLarger;
if (ABS(measuredSize.width - size.width) < thresholdSize.width) {
result = result | RCTTextSizeComparisonWithinRange;
}
return result;
}
- (void)scaleFontSizeWithRatio:(CGFloat)ratio
minimumFontSize:(CGFloat)minimumFontSize
maximumFontSize:(CGFloat)maximumFontSize
{
[self beginEditing];
[self enumerateAttribute:NSFontAttributeName
inRange:(NSRange){0, self.length}
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
usingBlock:
^(UIFont *_Nullable font, NSRange range, BOOL *_Nonnull stop) {
if (!font) {
return;
}
CGFloat fontSize = MAX(MIN(font.pointSize * ratio, maximumFontSize), minimumFontSize);
[self addAttribute:NSFontAttributeName
value:[font fontWithSize:fontSize]
range:range];
}
];
[self endEditing];
}
@end

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTShadowView.h>
#import "RCTBaseTextShadowView.h"
NS_ASSUME_NONNULL_BEGIN
@interface RCTTextShadowView : RCTBaseTextShadowView
- (instancetype)initWithBridge:(RCTBridge *)bridge;
@property (nonatomic, assign) NSInteger maximumNumberOfLines;
@property (nonatomic, assign) NSLineBreakMode lineBreakMode;
@property (nonatomic, assign) BOOL adjustsFontSizeToFit;
@property (nonatomic, assign) CGFloat minimumFontScale;
- (void)uiManagerWillPerformMounting;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,381 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTTextShadowView.h"
#import <React/RCTBridge.h>
#import <React/RCTShadowView+Layout.h>
#import <React/RCTUIManager.h>
#import <yoga/Yoga.h>
#import "NSTextStorage+FontScaling.h"
#import "RCTTextView.h"
@implementation RCTTextShadowView
{
__weak RCTBridge *_bridge;
BOOL _needsUpdateView;
NSMapTable<id, NSTextStorage *> *_cachedTextStorages;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
{
if (self = [super init]) {
_bridge = bridge;
_cachedTextStorages = [NSMapTable strongToStrongObjectsMapTable];
_needsUpdateView = YES;
YGNodeSetMeasureFunc(self.yogaNode, RCTTextShadowViewMeasure);
YGNodeSetBaselineFunc(self.yogaNode, RCTTextShadowViewBaseline);
}
return self;
}
- (BOOL)isYogaLeafNode
{
return YES;
}
- (void)dirtyLayout
{
[super dirtyLayout];
YGNodeMarkDirty(self.yogaNode);
[self invalidateCache];
}
- (void)invalidateCache
{
[_cachedTextStorages removeAllObjects];
_needsUpdateView = YES;
}
#pragma mark - RCTUIManagerObserver
- (void)uiManagerWillPerformMounting
{
if (YGNodeIsDirty(self.yogaNode)) {
return;
}
if (!_needsUpdateView) {
return;
}
_needsUpdateView = NO;
CGRect contentFrame = self.contentFrame;
NSTextStorage *textStorage = [self textStorageAndLayoutManagerThatFitsSize:self.contentFrame.size
exclusiveOwnership:YES];
NSNumber *tag = self.reactTag;
NSMutableArray<NSNumber *> *descendantViewTags = [NSMutableArray new];
[textStorage enumerateAttribute:RCTBaseTextShadowViewEmbeddedShadowViewAttributeName
inRange:NSMakeRange(0, textStorage.length)
options:0
usingBlock:
^(RCTShadowView *shadowView, NSRange range, __unused BOOL *stop) {
if (!shadowView) {
return;
}
[descendantViewTags addObject:shadowView.reactTag];
}
];
[_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
RCTTextView *textView = (RCTTextView *)viewRegistry[tag];
if (!textView) {
return;
}
NSMutableArray<UIView *> *descendantViews =
[NSMutableArray arrayWithCapacity:descendantViewTags.count];
[descendantViewTags enumerateObjectsUsingBlock:^(NSNumber *_Nonnull descendantViewTag, NSUInteger index, BOOL *_Nonnull stop) {
UIView *descendantView = viewRegistry[descendantViewTag];
if (!descendantView) {
return;
}
[descendantViews addObject:descendantView];
}];
// Removing all references to Shadow Views to avoid unnececery retainning.
[textStorage removeAttribute:RCTBaseTextShadowViewEmbeddedShadowViewAttributeName range:NSMakeRange(0, textStorage.length)];
[textView setTextStorage:textStorage
contentFrame:contentFrame
descendantViews:descendantViews];
}];
}
- (void)postprocessAttributedText:(NSMutableAttributedString *)attributedText
{
__block CGFloat maximumLineHeight = 0;
[attributedText enumerateAttribute:NSParagraphStyleAttributeName
inRange:NSMakeRange(0, attributedText.length)
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
usingBlock:
^(NSParagraphStyle *paragraphStyle, __unused NSRange range, __unused BOOL *stop) {
if (!paragraphStyle) {
return;
}
maximumLineHeight = MAX(paragraphStyle.maximumLineHeight, maximumLineHeight);
}
];
if (maximumLineHeight == 0) {
// `lineHeight` was not specified, nothing to do.
return;
}
[attributedText beginEditing];
[attributedText enumerateAttribute:NSFontAttributeName
inRange:NSMakeRange(0, attributedText.length)
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
usingBlock:
^(UIFont *font, NSRange range, __unused BOOL *stop) {
if (!font) {
return;
}
if (maximumLineHeight <= font.lineHeight) {
return;
}
CGFloat baseLineOffset = maximumLineHeight / 2.0 - font.lineHeight / 2.0;
[attributedText addAttribute:NSBaselineOffsetAttributeName
value:@(baseLineOffset)
range:range];
}
];
[attributedText endEditing];
}
- (NSAttributedString *)attributedTextWithMeasuredAttachmentsThatFitSize:(CGSize)size
{
NSMutableAttributedString *attributedText =
[[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTextWithBaseTextAttributes:nil]];
[attributedText beginEditing];
[attributedText enumerateAttribute:RCTBaseTextShadowViewEmbeddedShadowViewAttributeName
inRange:NSMakeRange(0, attributedText.length)
options:0
usingBlock:
^(RCTShadowView *shadowView, NSRange range, __unused BOOL *stop) {
if (!shadowView) {
return;
}
CGSize fittingSize = [shadowView sizeThatFitsMinimumSize:CGSizeZero
maximumSize:size];
NSTextAttachment *attachment = [NSTextAttachment new];
attachment.bounds = (CGRect){CGPointZero, fittingSize};
[attributedText addAttribute:NSAttachmentAttributeName value:attachment range:range];
}
];
[attributedText endEditing];
return [attributedText copy];
}
- (NSTextStorage *)textStorageAndLayoutManagerThatFitsSize:(CGSize)size
exclusiveOwnership:(BOOL)exclusiveOwnership
{
NSValue *key = [NSValue valueWithCGSize:size];
NSTextStorage *cachedTextStorage = [_cachedTextStorages objectForKey:key];
if (cachedTextStorage) {
if (exclusiveOwnership) {
[_cachedTextStorages removeObjectForKey:key];
}
return cachedTextStorage;
}
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size];
textContainer.lineFragmentPadding = 0.0; // Note, the default value is 5.
textContainer.lineBreakMode =
_maximumNumberOfLines > 0 ? _lineBreakMode : NSLineBreakByClipping;
textContainer.maximumNumberOfLines = _maximumNumberOfLines;
NSLayoutManager *layoutManager = [NSLayoutManager new];
[layoutManager addTextContainer:textContainer];
NSTextStorage *textStorage =
[[NSTextStorage alloc] initWithAttributedString:[self attributedTextWithMeasuredAttachmentsThatFitSize:size]];
[self postprocessAttributedText:textStorage];
[textStorage addLayoutManager:layoutManager];
if (_adjustsFontSizeToFit) {
CGFloat minimumFontSize =
MAX(_minimumFontScale * (self.textAttributes.effectiveFont.pointSize), 4.0);
[textStorage scaleFontSizeToFitSize:size
minimumFontSize:minimumFontSize
maximumFontSize:self.textAttributes.effectiveFont.pointSize];
}
if (!exclusiveOwnership) {
[_cachedTextStorages setObject:textStorage forKey:key];
}
return textStorage;
}
- (void)layoutWithMetrics:(RCTLayoutMetrics)layoutMetrics
layoutContext:(RCTLayoutContext)layoutContext
{
// If the view got new `contentFrame`, we have to redraw it because
// and sizes of embedded views may change.
if (!CGRectEqualToRect(self.layoutMetrics.contentFrame, layoutMetrics.contentFrame)) {
_needsUpdateView = YES;
}
if (self.textAttributes.layoutDirection != layoutMetrics.layoutDirection) {
self.textAttributes.layoutDirection = layoutMetrics.layoutDirection;
[self invalidateCache];
}
[super layoutWithMetrics:layoutMetrics layoutContext:layoutContext];
}
- (void)layoutSubviewsWithContext:(RCTLayoutContext)layoutContext
{
NSTextStorage *textStorage =
[self textStorageAndLayoutManagerThatFitsSize:self.availableSize
exclusiveOwnership:NO];
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
NSRange characterRange = [layoutManager characterRangeForGlyphRange:glyphRange
actualGlyphRange:NULL];
[textStorage enumerateAttribute:RCTBaseTextShadowViewEmbeddedShadowViewAttributeName
inRange:characterRange
options:0
usingBlock:
^(RCTShadowView *shadowView, NSRange range, BOOL *stop) {
if (!shadowView) {
return;
}
CGRect glyphRect = [layoutManager boundingRectForGlyphRange:range
inTextContainer:textContainer];
NSTextAttachment *attachment =
[textStorage attribute:NSAttachmentAttributeName atIndex:range.location effectiveRange:nil];
CGSize attachmentSize = attachment.bounds.size;
UIFont *font = [textStorage attribute:NSFontAttributeName atIndex:range.location effectiveRange:nil];
CGRect frame = {{
RCTRoundPixelValue(glyphRect.origin.x),
RCTRoundPixelValue(glyphRect.origin.y + glyphRect.size.height - attachmentSize.height + font.descender)
}, {
RCTRoundPixelValue(attachmentSize.width),
RCTRoundPixelValue(attachmentSize.height)
}};
RCTLayoutContext localLayoutContext = layoutContext;
localLayoutContext.absolutePosition.x += frame.origin.x;
localLayoutContext.absolutePosition.y += frame.origin.y;
[shadowView layoutWithMinimumSize:frame.size
maximumSize:frame.size
layoutDirection:self.layoutMetrics.layoutDirection
layoutContext:localLayoutContext];
// Reinforcing a proper frame origin for the Shadow View.
RCTLayoutMetrics localLayoutMetrics = shadowView.layoutMetrics;
localLayoutMetrics.frame.origin = frame.origin;
[shadowView layoutWithMetrics:localLayoutMetrics layoutContext:localLayoutContext];
}
];
}
- (CGFloat)lastBaselineForSize:(CGSize)size
{
NSAttributedString *attributedText =
[self textStorageAndLayoutManagerThatFitsSize:size exclusiveOwnership:NO];
__block CGFloat maximumDescender = 0.0;
[attributedText enumerateAttribute:NSFontAttributeName
inRange:NSMakeRange(0, attributedText.length)
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
usingBlock:
^(UIFont *font, NSRange range, __unused BOOL *stop) {
if (maximumDescender > font.descender) {
maximumDescender = font.descender;
}
}
];
return size.height + maximumDescender;
}
static YGSize RCTTextShadowViewMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode)
{
CGSize maximumSize = (CGSize){
widthMode == YGMeasureModeUndefined ? CGFLOAT_MAX : RCTCoreGraphicsFloatFromYogaFloat(width),
heightMode == YGMeasureModeUndefined ? CGFLOAT_MAX : RCTCoreGraphicsFloatFromYogaFloat(height),
};
RCTTextShadowView *shadowTextView = (__bridge RCTTextShadowView *)YGNodeGetContext(node);
NSTextStorage *textStorage =
[shadowTextView textStorageAndLayoutManagerThatFitsSize:maximumSize
exclusiveOwnership:NO];
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
[layoutManager ensureLayoutForTextContainer:textContainer];
CGSize size = [layoutManager usedRectForTextContainer:textContainer].size;
CGFloat letterSpacing = shadowTextView.textAttributes.letterSpacing;
if (!isnan(letterSpacing) && letterSpacing < 0) {
size.width -= letterSpacing;
}
size = (CGSize){
MIN(RCTCeilPixelValue(size.width), maximumSize.width),
MIN(RCTCeilPixelValue(size.height), maximumSize.height)
};
// Adding epsilon value illuminates problems with converting values from
// `double` to `float`, and then rounding them to pixel grid in Yoga.
CGFloat epsilon = 0.001;
return (YGSize){
RCTYogaFloatFromCoreGraphicsFloat(size.width + epsilon),
RCTYogaFloatFromCoreGraphicsFloat(size.height + epsilon)
};
}
static float RCTTextShadowViewBaseline(YGNodeRef node, const float width, const float height)
{
RCTTextShadowView *shadowTextView = (__bridge RCTTextShadowView *)YGNodeGetContext(node);
CGSize size = (CGSize){
RCTCoreGraphicsFloatFromYogaFloat(width),
RCTCoreGraphicsFloatFromYogaFloat(height)
};
CGFloat lastBaseline = [shadowTextView lastBaselineForSize:size];
return RCTYogaFloatFromCoreGraphicsFloat(lastBaseline);
}
@end

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface RCTTextView : UIView
@property (nonatomic, assign) BOOL selectable;
- (void)setTextStorage:(NSTextStorage *)textStorage
contentFrame:(CGRect)contentFrame
descendantViews:(NSArray<UIView *> *)descendantViews;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,267 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTTextView.h"
#import <MobileCoreServices/UTCoreTypes.h>
#import <React/RCTUtils.h>
#import <React/UIView+React.h>
#import "RCTTextShadowView.h"
@implementation RCTTextView
{
CAShapeLayer *_highlightLayer;
UILongPressGestureRecognizer *_longPressGestureRecognizer;
NSArray<UIView *> *_Nullable _descendantViews;
NSTextStorage *_Nullable _textStorage;
CGRect _contentFrame;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.isAccessibilityElement = YES;
self.accessibilityTraits |= UIAccessibilityTraitStaticText;
self.opaque = NO;
self.contentMode = UIViewContentModeRedraw;
}
return self;
}
- (NSString *)description
{
NSString *superDescription = super.description;
NSRange semicolonRange = [superDescription rangeOfString:@";"];
NSString *replacement = [NSString stringWithFormat:@"; reactTag: %@; text: %@", self.reactTag, _textStorage.string];
return [superDescription stringByReplacingCharactersInRange:semicolonRange withString:replacement];
}
- (void)setSelectable:(BOOL)selectable
{
if (_selectable == selectable) {
return;
}
_selectable = selectable;
if (_selectable) {
[self enableContextMenu];
}
else {
[self disableContextMenu];
}
}
- (void)reactSetFrame:(CGRect)frame
{
// Text looks super weird if its frame is animated.
// This disables the frame animation, without affecting opacity, etc.
[UIView performWithoutAnimation:^{
[super reactSetFrame:frame];
}];
}
- (void)didUpdateReactSubviews
{
// Do nothing, as subviews are managed by `setTextStorage:` method
}
- (void)setTextStorage:(NSTextStorage *)textStorage
contentFrame:(CGRect)contentFrame
descendantViews:(NSArray<UIView *> *)descendantViews
{
_textStorage = textStorage;
_contentFrame = contentFrame;
// FIXME: Optimize this.
for (UIView *view in _descendantViews) {
[view removeFromSuperview];
}
_descendantViews = descendantViews;
for (UIView *view in descendantViews) {
[self addSubview:view];
}
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
if (!_textStorage) {
return;
}
NSLayoutManager *layoutManager = _textStorage.layoutManagers.firstObject;
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
[layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:_contentFrame.origin];
[layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:_contentFrame.origin];
__block UIBezierPath *highlightPath = nil;
NSRange characterRange = [layoutManager characterRangeForGlyphRange:glyphRange
actualGlyphRange:NULL];
[_textStorage enumerateAttribute:RCTTextAttributesIsHighlightedAttributeName
inRange:characterRange
options:0
usingBlock:
^(NSNumber *value, NSRange range, __unused BOOL *stop) {
if (!value.boolValue) {
return;
}
[layoutManager enumerateEnclosingRectsForGlyphRange:range
withinSelectedGlyphRange:range
inTextContainer:textContainer
usingBlock:
^(CGRect enclosingRect, __unused BOOL *anotherStop) {
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(enclosingRect, -2, -2) cornerRadius:2];
if (highlightPath) {
[highlightPath appendPath:path];
} else {
highlightPath = path;
}
}
];
}];
if (highlightPath) {
if (!_highlightLayer) {
_highlightLayer = [CAShapeLayer layer];
_highlightLayer.fillColor = [UIColor colorWithWhite:0 alpha:0.25].CGColor;
[self.layer addSublayer:_highlightLayer];
}
_highlightLayer.position = _contentFrame.origin;
_highlightLayer.path = highlightPath.CGPath;
} else {
[_highlightLayer removeFromSuperlayer];
_highlightLayer = nil;
}
}
- (NSNumber *)reactTagAtPoint:(CGPoint)point
{
NSNumber *reactTag = self.reactTag;
CGFloat fraction;
NSLayoutManager *layoutManager = _textStorage.layoutManagers.firstObject;
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
NSUInteger characterIndex = [layoutManager characterIndexForPoint:point
inTextContainer:textContainer
fractionOfDistanceBetweenInsertionPoints:&fraction];
// If the point is not before (fraction == 0.0) the first character and not
// after (fraction == 1.0) the last character, then the attribute is valid.
if (_textStorage.length > 0 && (fraction > 0 || characterIndex > 0) && (fraction < 1 || characterIndex < _textStorage.length - 1)) {
reactTag = [_textStorage attribute:RCTTextAttributesTagAttributeName atIndex:characterIndex effectiveRange:NULL];
}
return reactTag;
}
- (void)didMoveToWindow
{
[super didMoveToWindow];
if (!self.window) {
self.layer.contents = nil;
if (_highlightLayer) {
[_highlightLayer removeFromSuperlayer];
_highlightLayer = nil;
}
} else if (_textStorage) {
[self setNeedsDisplay];
}
}
#pragma mark - Accessibility
- (NSString *)accessibilityLabel
{
NSString *superAccessibilityLabel = [super accessibilityLabel];
if (superAccessibilityLabel) {
return superAccessibilityLabel;
}
return _textStorage.string;
}
#pragma mark - Context Menu
- (void)enableContextMenu
{
_longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
[self addGestureRecognizer:_longPressGestureRecognizer];
}
- (void)disableContextMenu
{
[self removeGestureRecognizer:_longPressGestureRecognizer];
_longPressGestureRecognizer = nil;
}
- (void)handleLongPress:(UILongPressGestureRecognizer *)gesture
{
#if !TARGET_OS_TV
UIMenuController *menuController = [UIMenuController sharedMenuController];
if (menuController.isMenuVisible) {
return;
}
if (!self.isFirstResponder) {
[self becomeFirstResponder];
}
[menuController setTargetRect:self.bounds inView:self];
[menuController setMenuVisible:YES animated:YES];
#endif
}
- (BOOL)canBecomeFirstResponder
{
return _selectable;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (_selectable && action == @selector(copy:)) {
return YES;
}
return [self.nextResponder canPerformAction:action withSender:sender];
}
- (void)copy:(id)sender
{
#if !TARGET_OS_TV
NSAttributedString *attributedText = _textStorage;
NSMutableDictionary *item = [NSMutableDictionary new];
NSData *rtf = [attributedText dataFromRange:NSMakeRange(0, attributedText.length)
documentAttributes:@{NSDocumentTypeDocumentAttribute: NSRTFDTextDocumentType}
error:nil];
if (rtf) {
[item setObject:rtf forKey:(id)kUTTypeFlatRTFD];
}
[item setObject:attributedText.string forKey:(id)kUTTypeUTF8PlainText];
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
pasteboard.items = @[item];
#endif
}
@end

View File

@@ -0,0 +1,14 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTViewManager.h>
#import "RCTBaseTextViewManager.h"
@interface RCTTextViewManager : RCTBaseTextViewManager
@end

View File

@@ -0,0 +1,96 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTTextViewManager.h"
#import <React/RCTAccessibilityManager.h>
#import <React/RCTShadowView+Layout.h>
#import <React/RCTShadowView.h>
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerUtils.h>
#import <React/RCTUIManagerObserverCoordinator.h>
#import "RCTTextShadowView.h"
#import "RCTTextView.h"
@interface RCTTextViewManager () <RCTUIManagerObserver>
@end
@implementation RCTTextViewManager
{
NSHashTable<RCTTextShadowView *> *_shadowViews;
CGFloat _fontSizeMultiplier;
}
RCT_EXPORT_MODULE(RCTText)
RCT_REMAP_SHADOW_PROPERTY(numberOfLines, maximumNumberOfLines, NSInteger)
RCT_REMAP_SHADOW_PROPERTY(ellipsizeMode, lineBreakMode, NSLineBreakMode)
RCT_REMAP_SHADOW_PROPERTY(adjustsFontSizeToFit, adjustsFontSizeToFit, BOOL)
RCT_REMAP_SHADOW_PROPERTY(minimumFontScale, minimumFontScale, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(selectable, BOOL)
- (void)setBridge:(RCTBridge *)bridge
{
[super setBridge:bridge];
_shadowViews = [NSHashTable weakObjectsHashTable];
[bridge.uiManager.observerCoordinator addObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleDidUpdateMultiplierNotification)
name:RCTAccessibilityManagerDidUpdateMultiplierNotification
object:bridge.accessibilityManager];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (UIView *)view
{
return [RCTTextView new];
}
- (RCTShadowView *)shadowView
{
RCTTextShadowView *shadowView = [[RCTTextShadowView alloc] initWithBridge:self.bridge];
shadowView.textAttributes.fontSizeMultiplier = self.bridge.accessibilityManager.multiplier;
[_shadowViews addObject:shadowView];
return shadowView;
}
#pragma mark - RCTUIManagerObserver
- (void)uiManagerWillPerformMounting:(__unused RCTUIManager *)uiManager
{
for (RCTTextShadowView *shadowView in _shadowViews) {
[shadowView uiManagerWillPerformMounting];
}
}
#pragma mark - Font Size Multiplier
- (void)handleDidUpdateMultiplierNotification
{
CGFloat fontSizeMultiplier = self.bridge.accessibilityManager.multiplier;
NSHashTable<RCTTextShadowView *> *shadowViews = _shadowViews;
RCTExecuteOnUIManagerQueue(^{
for (RCTTextShadowView *shadowView in shadowViews) {
shadowView.textAttributes.fontSizeMultiplier = fontSizeMultiplier;
[shadowView dirtyLayout];
}
[self.bridge.uiManager setNeedsLayout];
});
}
@end

View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextInputView.h"
NS_ASSUME_NONNULL_BEGIN
@interface RCTMultilineTextInputView : RCTBaseTextInputView
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,87 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTMultilineTextInputView.h"
#import <React/RCTUtils.h>
#import "RCTUITextView.h"
@implementation RCTMultilineTextInputView
{
RCTUITextView *_backedTextInputView;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
{
if (self = [super initWithBridge:bridge]) {
// `blurOnSubmit` defaults to `false` for <TextInput multiline={true}> by design.
self.blurOnSubmit = NO;
_backedTextInputView = [[RCTUITextView alloc] initWithFrame:self.bounds];
_backedTextInputView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_backedTextInputView.backgroundColor = [UIColor clearColor];
_backedTextInputView.textColor = [UIColor blackColor];
// This line actually removes 5pt (default value) left and right padding in UITextView.
_backedTextInputView.textContainer.lineFragmentPadding = 0;
#if !TARGET_OS_TV
_backedTextInputView.scrollsToTop = NO;
#endif
_backedTextInputView.scrollEnabled = YES;
_backedTextInputView.textInputDelegate = self;
[self addSubview:_backedTextInputView];
}
return self;
}
RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)coder)
- (id<RCTBackedTextInputViewProtocol>)backedTextInputView
{
return _backedTextInputView;
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
RCTDirectEventBlock onScroll = self.onScroll;
if (onScroll) {
CGPoint contentOffset = scrollView.contentOffset;
CGSize contentSize = scrollView.contentSize;
CGSize size = scrollView.bounds.size;
UIEdgeInsets contentInset = scrollView.contentInset;
onScroll(@{
@"contentOffset": @{
@"x": @(contentOffset.x),
@"y": @(contentOffset.y)
},
@"contentInset": @{
@"top": @(contentInset.top),
@"left": @(contentInset.left),
@"bottom": @(contentInset.bottom),
@"right": @(contentInset.right)
},
@"contentSize": @{
@"width": @(contentSize.width),
@"height": @(contentSize.height)
},
@"layoutMeasurement": @{
@"width": @(size.width),
@"height": @(size.height)
},
@"zoomScale": @(scrollView.zoomScale ?: 1),
});
}
}
@end

View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextInputViewManager.h"
NS_ASSUME_NONNULL_BEGIN
@interface RCTMultilineTextInputViewManager : RCTBaseTextInputViewManager
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTMultilineTextInputViewManager.h"
#import "RCTMultilineTextInputView.h"
@implementation RCTMultilineTextInputViewManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
return [[RCTMultilineTextInputView alloc] initWithBridge:self.bridge];
}
#pragma mark - Multiline <TextInput> (aka TextView) specific properties
#if !TARGET_OS_TV
RCT_REMAP_VIEW_PROPERTY(dataDetectorTypes, backedTextInputView.dataDetectorTypes, UIDataDetectorTypes)
#endif
@end

View File

@@ -0,0 +1,43 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import "RCTBackedTextInputViewProtocol.h"
#import "RCTBackedTextInputDelegate.h"
NS_ASSUME_NONNULL_BEGIN
/*
* Just regular UITextView... but much better!
*/
@interface RCTUITextView : UITextView <RCTBackedTextInputViewProtocol>
- (instancetype)initWithFrame:(CGRect)frame textContainer:(nullable NSTextContainer *)textContainer NS_UNAVAILABLE;
- (instancetype)initWithCoder:(NSCoder *)decoder NS_UNAVAILABLE;
@property (nonatomic, weak) id<RCTBackedTextInputDelegate> textInputDelegate;
@property (nonatomic, assign) BOOL contextMenuHidden;
@property (nonatomic, assign, readonly) BOOL textWasPasted;
@property (nonatomic, copy, nullable) NSString *placeholder;
@property (nonatomic, strong, nullable) UIColor *placeholderColor;
@property (nonatomic, assign) CGFloat preferredMaxLayoutWidth;
// The `clearButtonMode` property actually is not supported yet;
// it's declared here only to conform to the interface.
@property (nonatomic, assign) UITextFieldViewMode clearButtonMode;
// The `caretHidden` property actually is not supported yet;
// it's declared here only to conform to the interface.
@property (nonatomic, assign) BOOL caretHidden;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,250 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTUITextView.h"
#import <React/RCTUtils.h>
#import <React/UIView+React.h>
#import "RCTBackedTextInputDelegateAdapter.h"
@implementation RCTUITextView
{
UILabel *_placeholderView;
UITextView *_detachedTextView;
RCTBackedTextViewDelegateAdapter *_textInputDelegateAdapter;
}
static UIFont *defaultPlaceholderFont()
{
return [UIFont systemFontOfSize:17];
}
static UIColor *defaultPlaceholderColor()
{
// Default placeholder color from UITextField.
return [UIColor colorWithRed:0 green:0 blue:0.0980392 alpha:0.22];
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(textDidChange)
name:UITextViewTextDidChangeNotification
object:self];
_placeholderView = [[UILabel alloc] initWithFrame:self.bounds];
_placeholderView.isAccessibilityElement = NO;
_placeholderView.numberOfLines = 0;
_placeholderView.textColor = defaultPlaceholderColor();
[self addSubview:_placeholderView];
_textInputDelegateAdapter = [[RCTBackedTextViewDelegateAdapter alloc] initWithTextView:self];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (NSString *)accessibilityLabel
{
NSMutableString *accessibilityLabel = [NSMutableString new];
NSString *superAccessibilityLabel = [super accessibilityLabel];
if (superAccessibilityLabel.length > 0) {
[accessibilityLabel appendString:superAccessibilityLabel];
}
if (self.placeholder.length > 0 && self.attributedText.string.length == 0) {
if (accessibilityLabel.length > 0) {
[accessibilityLabel appendString:@" "];
}
[accessibilityLabel appendString:self.placeholder];
}
return accessibilityLabel;
}
#pragma mark - Properties
- (void)setPlaceholder:(NSString *)placeholder
{
_placeholder = placeholder;
_placeholderView.text = _placeholder;
}
- (void)setPlaceholderColor:(UIColor *)placeholderColor
{
_placeholderColor = placeholderColor;
_placeholderView.textColor = _placeholderColor ?: defaultPlaceholderColor();
}
- (void)textDidChange
{
_textWasPasted = NO;
[self invalidatePlaceholderVisibility];
}
#pragma mark - Overrides
- (void)setFont:(UIFont *)font
{
[super setFont:font];
_placeholderView.font = font ?: defaultPlaceholderFont();
}
- (void)setTextAlignment:(NSTextAlignment)textAlignment
{
[super setTextAlignment:textAlignment];
_placeholderView.textAlignment = textAlignment;
}
- (void)setText:(NSString *)text
{
[super setText:text];
[self textDidChange];
}
- (void)setAttributedText:(NSAttributedString *)attributedText
{
[super setAttributedText:attributedText];
[self textDidChange];
}
#pragma mark - Overrides
- (void)setSelectedTextRange:(UITextRange *)selectedTextRange notifyDelegate:(BOOL)notifyDelegate
{
if (!notifyDelegate) {
// We have to notify an adapter that following selection change was initiated programmatically,
// so the adapter must not generate a notification for it.
[_textInputDelegateAdapter skipNextTextInputDidChangeSelectionEventWithTextRange:selectedTextRange];
}
[super setSelectedTextRange:selectedTextRange];
}
- (void)paste:(id)sender
{
[super paste:sender];
_textWasPasted = YES;
}
- (void)setContentOffset:(CGPoint)contentOffset animated:(__unused BOOL)animated
{
// Turning off scroll animation.
// This fixes the problem also known as "flaky scrolling".
[super setContentOffset:contentOffset animated:NO];
}
#pragma mark - Layout
- (CGFloat)preferredMaxLayoutWidth
{
// Returning size DOES contain `textContainerInset` (aka `padding`).
return _preferredMaxLayoutWidth ?: self.placeholderSize.width;
}
- (CGSize)placeholderSize
{
UIEdgeInsets textContainerInset = self.textContainerInset;
NSString *placeholder = self.placeholder ?: @"";
CGSize placeholderSize = [placeholder sizeWithAttributes:@{NSFontAttributeName: self.font ?: defaultPlaceholderFont()}];
placeholderSize = CGSizeMake(RCTCeilPixelValue(placeholderSize.width), RCTCeilPixelValue(placeholderSize.height));
placeholderSize.width += textContainerInset.left + textContainerInset.right;
placeholderSize.height += textContainerInset.top + textContainerInset.bottom;
// Returning size DOES contain `textContainerInset` (aka `padding`; as `sizeThatFits:` does).
return placeholderSize;
}
- (CGSize)contentSize
{
CGSize contentSize = super.contentSize;
CGSize placeholderSize = self.placeholderSize;
// When a text input is empty, it actually displays a placehoder.
// So, we have to consider `placeholderSize` as a minimum `contentSize`.
// Returning size DOES contain `textContainerInset` (aka `padding`).
return CGSizeMake(
MAX(contentSize.width, placeholderSize.width),
MAX(contentSize.height, placeholderSize.height));
}
- (void)layoutSubviews
{
[super layoutSubviews];
CGRect textFrame = UIEdgeInsetsInsetRect(self.bounds, self.textContainerInset);
CGFloat placeholderHeight = [_placeholderView sizeThatFits:textFrame.size].height;
textFrame.size.height = MIN(placeholderHeight, textFrame.size.height);
_placeholderView.frame = textFrame;
}
- (CGSize)intrinsicContentSize
{
// Returning size DOES contain `textContainerInset` (aka `padding`).
return [self sizeThatFits:CGSizeMake(self.preferredMaxLayoutWidth, CGFLOAT_MAX)];
}
- (CGSize)sizeThatFits:(CGSize)size
{
// Returned fitting size depends on text size and placeholder size.
CGSize textSize = [self fixedSizeThatFits:size];
CGSize placeholderSize = self.placeholderSize;
// Returning size DOES contain `textContainerInset` (aka `padding`).
return CGSizeMake(MAX(textSize.width, placeholderSize.width), MAX(textSize.height, placeholderSize.height));
}
- (CGSize)fixedSizeThatFits:(CGSize)size
{
// UITextView on iOS 8 has a bug that automatically scrolls to the top
// when calling `sizeThatFits:`. Use a copy so that self is not screwed up.
static BOOL useCustomImplementation = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
useCustomImplementation = ![[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){9,0,0}];
});
if (!useCustomImplementation) {
return [super sizeThatFits:size];
}
if (!_detachedTextView) {
_detachedTextView = [UITextView new];
}
_detachedTextView.attributedText = self.attributedText;
_detachedTextView.font = self.font;
_detachedTextView.textContainerInset = self.textContainerInset;
return [_detachedTextView sizeThatFits:size];
}
#pragma mark - Context Menu
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (_contextMenuHidden) {
return NO;
}
return [super canPerformAction:action withSender:sender];
}
#pragma mark - Placeholder
- (void)invalidatePlaceholderVisibility
{
BOOL isVisible = _placeholder.length != 0 && self.attributedText.length == 0;
_placeholderView.hidden = !isVisible;
}
@end

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
@protocol RCTBackedTextInputViewProtocol;
NS_ASSUME_NONNULL_BEGIN
@protocol RCTBackedTextInputDelegate <NSObject>
- (BOOL)textInputShouldBeginEditing; // Return `NO` to disallow editing.
- (void)textInputDidBeginEditing;
- (BOOL)textInputShouldEndEditing; // Return `YES` to allow editing to stop and to resign first responder status. `NO` to disallow the editing session to end.
- (void)textInputDidEndEditing; // May be called if forced even if `textInputShouldEndEditing` returns `NO` (e.g. view removed from window) or `[textInput endEditing:YES]` called.
- (BOOL)textInputShouldReturn; // May be called right before `textInputShouldEndEditing` if "Return" button was pressed.
- (void)textInputDidReturn;
- (BOOL)textInputShouldChangeTextInRange:(NSRange)range replacementText:(NSString *)string; // Return NO to not change text.
- (void)textInputDidChange;
- (void)textInputDidChangeSelection;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import "RCTBackedTextInputViewProtocol.h"
#import "RCTBackedTextInputDelegate.h"
NS_ASSUME_NONNULL_BEGIN
#pragma mark - RCTBackedTextFieldDelegateAdapter (for UITextField)
@interface RCTBackedTextFieldDelegateAdapter : NSObject
- (instancetype)initWithTextField:(UITextField<RCTBackedTextInputViewProtocol> *)backedTextInputView;
- (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)textRange;
- (void)selectedTextRangeWasSet;
@end
#pragma mark - RCTBackedTextViewDelegateAdapter (for UITextView)
@interface RCTBackedTextViewDelegateAdapter : NSObject
- (instancetype)initWithTextView:(UITextView<RCTBackedTextInputViewProtocol> *)backedTextInputView;
- (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)textRange;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,235 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBackedTextInputDelegateAdapter.h"
#pragma mark - RCTBackedTextFieldDelegateAdapter (for UITextField)
static void *TextFieldSelectionObservingContext = &TextFieldSelectionObservingContext;
@interface RCTBackedTextFieldDelegateAdapter () <UITextFieldDelegate>
@end
@implementation RCTBackedTextFieldDelegateAdapter {
__weak UITextField<RCTBackedTextInputViewProtocol> *_backedTextInputView;
BOOL _textDidChangeIsComing;
UITextRange *_previousSelectedTextRange;
}
- (instancetype)initWithTextField:(UITextField<RCTBackedTextInputViewProtocol> *)backedTextInputView
{
if (self = [super init]) {
_backedTextInputView = backedTextInputView;
backedTextInputView.delegate = self;
[_backedTextInputView addTarget:self action:@selector(textFieldDidChange) forControlEvents:UIControlEventEditingChanged];
[_backedTextInputView addTarget:self action:@selector(textFieldDidEndEditingOnExit) forControlEvents:UIControlEventEditingDidEndOnExit];
}
return self;
}
- (void)dealloc
{
[_backedTextInputView removeTarget:self action:nil forControlEvents:UIControlEventEditingChanged];
[_backedTextInputView removeTarget:self action:nil forControlEvents:UIControlEventEditingDidEndOnExit];
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldBeginEditing:(__unused UITextField *)textField
{
return [_backedTextInputView.textInputDelegate textInputShouldBeginEditing];
}
- (void)textFieldDidBeginEditing:(__unused UITextField *)textField
{
[_backedTextInputView.textInputDelegate textInputDidBeginEditing];
}
- (BOOL)textFieldShouldEndEditing:(__unused UITextField *)textField
{
return [_backedTextInputView.textInputDelegate textInputShouldEndEditing];
}
- (void)textFieldDidEndEditing:(__unused UITextField *)textField
{
if (_textDidChangeIsComing) {
// iOS does't call `textViewDidChange:` delegate method if the change was happened because of autocorrection
// which was triggered by losing focus. So, we call it manually.
_textDidChangeIsComing = NO;
[_backedTextInputView.textInputDelegate textInputDidChange];
}
[_backedTextInputView.textInputDelegate textInputDidEndEditing];
}
- (BOOL)textField:(__unused UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
BOOL result = [_backedTextInputView.textInputDelegate textInputShouldChangeTextInRange:range replacementText:string];
if (result) {
_textDidChangeIsComing = YES;
}
return result;
}
- (BOOL)textFieldShouldReturn:(__unused UITextField *)textField
{
return [_backedTextInputView.textInputDelegate textInputShouldReturn];
}
#pragma mark - UIControlEventEditing* Family Events
- (void)textFieldDidChange
{
_textDidChangeIsComing = NO;
[_backedTextInputView.textInputDelegate textInputDidChange];
// `selectedTextRangeWasSet` isn't triggered during typing.
[self textFieldProbablyDidChangeSelection];
}
- (void)textFieldDidEndEditingOnExit
{
[_backedTextInputView.textInputDelegate textInputDidReturn];
}
#pragma mark - UIKeyboardInput (private UIKit protocol)
// This method allows us to detect a [Backspace] `keyPress`
// even when there is no more text in the `UITextField`.
- (BOOL)keyboardInputShouldDelete:(__unused UITextField *)textField
{
[_backedTextInputView.textInputDelegate textInputShouldChangeTextInRange:NSMakeRange(0, 0) replacementText:@""];
return YES;
}
#pragma mark - Public Interface
- (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)textRange
{
_previousSelectedTextRange = textRange;
}
- (void)selectedTextRangeWasSet
{
[self textFieldProbablyDidChangeSelection];
}
#pragma mark - Generalization
- (void)textFieldProbablyDidChangeSelection
{
if ([_backedTextInputView.selectedTextRange isEqual:_previousSelectedTextRange]) {
return;
}
_previousSelectedTextRange = _backedTextInputView.selectedTextRange;
[_backedTextInputView.textInputDelegate textInputDidChangeSelection];
}
@end
#pragma mark - RCTBackedTextViewDelegateAdapter (for UITextView)
@interface RCTBackedTextViewDelegateAdapter () <UITextViewDelegate>
@end
@implementation RCTBackedTextViewDelegateAdapter {
__weak UITextView<RCTBackedTextInputViewProtocol> *_backedTextInputView;
BOOL _textDidChangeIsComing;
UITextRange *_previousSelectedTextRange;
}
- (instancetype)initWithTextView:(UITextView<RCTBackedTextInputViewProtocol> *)backedTextInputView
{
if (self = [super init]) {
_backedTextInputView = backedTextInputView;
backedTextInputView.delegate = self;
}
return self;
}
#pragma mark - UITextViewDelegate
- (BOOL)textViewShouldBeginEditing:(__unused UITextView *)textView
{
return [_backedTextInputView.textInputDelegate textInputShouldBeginEditing];
}
- (void)textViewDidBeginEditing:(__unused UITextView *)textView
{
[_backedTextInputView.textInputDelegate textInputDidBeginEditing];
}
- (BOOL)textViewShouldEndEditing:(__unused UITextView *)textView
{
return [_backedTextInputView.textInputDelegate textInputShouldEndEditing];
}
- (void)textViewDidEndEditing:(__unused UITextView *)textView
{
if (_textDidChangeIsComing) {
// iOS does't call `textViewDidChange:` delegate method if the change was happened because of autocorrection
// which was triggered by losing focus. So, we call it manually.
_textDidChangeIsComing = NO;
[_backedTextInputView.textInputDelegate textInputDidChange];
}
[_backedTextInputView.textInputDelegate textInputDidEndEditing];
}
- (BOOL)textView:(__unused UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
// Custom implementation of `textInputShouldReturn` and `textInputDidReturn` pair for `UITextView`.
if (!_backedTextInputView.textWasPasted && [text isEqualToString:@"\n"]) {
if ([_backedTextInputView.textInputDelegate textInputShouldReturn]) {
[_backedTextInputView.textInputDelegate textInputDidReturn];
[_backedTextInputView endEditing:NO];
return NO;
}
}
BOOL result = [_backedTextInputView.textInputDelegate textInputShouldChangeTextInRange:range replacementText:text];
if (result) {
_textDidChangeIsComing = YES;
}
return result;
}
- (void)textViewDidChange:(__unused UITextView *)textView
{
_textDidChangeIsComing = NO;
[_backedTextInputView.textInputDelegate textInputDidChange];
}
- (void)textViewDidChangeSelection:(__unused UITextView *)textView
{
[self textViewProbablyDidChangeSelection];
}
#pragma mark - Public Interface
- (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)textRange
{
_previousSelectedTextRange = textRange;
}
#pragma mark - Generalization
- (void)textViewProbablyDidChangeSelection
{
if ([_backedTextInputView.selectedTextRange isEqual:_previousSelectedTextRange]) {
return;
}
_previousSelectedTextRange = _backedTextInputView.selectedTextRange;
[_backedTextInputView.textInputDelegate textInputDidChangeSelection];
}
@end

View File

@@ -0,0 +1,43 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
@protocol RCTBackedTextInputDelegate;
NS_ASSUME_NONNULL_BEGIN
@protocol RCTBackedTextInputViewProtocol <UITextInput>
@property (nonatomic, strong, nullable) UIColor *textColor;
@property (nonatomic, strong, nullable) UIFont *font;
@property (nonatomic, copy, nullable) NSAttributedString *attributedText;
@property (nonatomic, copy, nullable) NSString *placeholder;
@property (nonatomic, strong, nullable) UIColor *placeholderColor;
@property (nonatomic, assign) NSTextAlignment textAlignment;
@property (nonatomic, assign, readonly) BOOL textWasPasted;
@property (nonatomic, assign) UIEdgeInsets textContainerInset;
@property (nonatomic, strong, nullable) UIView *inputAccessoryView;
@property (nonatomic, weak, nullable) id<RCTBackedTextInputDelegate> textInputDelegate;
@property (nonatomic, readonly) CGSize contentSize;
// This protocol disallows direct access to `selectedTextRange` property because
// unwise usage of it can break the `delegate` behavior. So, we always have to
// explicitly specify should `delegate` be notified about the change or not.
// If the change was initiated programmatically, we must NOT notify the delegate.
// If the change was a result of user actions (like typing or touches), we MUST notify the delegate.
- (void)setSelectedTextRange:(nullable UITextRange *)selectedTextRange NS_UNAVAILABLE;
- (void)setSelectedTextRange:(nullable UITextRange *)selectedTextRange notifyDelegate:(BOOL)notifyDelegate;
// This protocol disallows direct access to `text` property because
// unwise usage of it can break the `attributeText` behavior.
// Use `attributedText.string` instead.
@property (nonatomic, copy, nullable) NSString *text NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextShadowView.h"
NS_ASSUME_NONNULL_BEGIN
@interface RCTBaseTextInputShadowView : RCTBaseTextShadowView
- (instancetype)initWithBridge:(RCTBridge *)bridge;
@property (nonatomic, copy, nullable) NSString *text;
@property (nonatomic, copy, nullable) NSString *placeholder;
@property (nonatomic, assign) NSInteger maximumNumberOfLines;
@property (nonatomic, copy, nullable) RCTDirectEventBlock onContentSizeChange;
- (void)uiManagerWillPerformMounting;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,296 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextInputShadowView.h"
#import <React/RCTBridge.h>
#import <React/RCTShadowView+Layout.h>
#import <React/RCTUIManager.h>
#import <yoga/Yoga.h>
#import "NSTextStorage+FontScaling.h"
#import "RCTBaseTextInputView.h"
@implementation RCTBaseTextInputShadowView
{
__weak RCTBridge *_bridge;
NSAttributedString *_Nullable _previousAttributedText;
BOOL _needsUpdateView;
NSAttributedString *_Nullable _localAttributedText;
CGSize _previousContentSize;
NSTextStorage *_textStorage;
NSTextContainer *_textContainer;
NSLayoutManager *_layoutManager;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
{
if (self = [super init]) {
_bridge = bridge;
_needsUpdateView = YES;
YGNodeSetMeasureFunc(self.yogaNode, RCTBaseTextInputShadowViewMeasure);
YGNodeSetBaselineFunc(self.yogaNode, RCTTextInputShadowViewBaseline);
}
return self;
}
- (BOOL)isYogaLeafNode
{
return YES;
}
- (void)layoutSubviewsWithContext:(RCTLayoutContext)layoutContext
{
// Do nothing.
}
- (void)setLocalData:(NSObject *)localData
{
NSAttributedString *attributedText = (NSAttributedString *)localData;
if ([attributedText isEqualToAttributedString:_localAttributedText]) {
return;
}
_localAttributedText = attributedText;
[self dirtyLayout];
}
- (void)dirtyLayout
{
[super dirtyLayout];
_needsUpdateView = YES;
YGNodeMarkDirty(self.yogaNode);
[self invalidateContentSize];
}
- (void)invalidateContentSize
{
if (!_onContentSizeChange) {
return;
}
CGSize maximumSize = self.layoutMetrics.frame.size;
if (_maximumNumberOfLines == 1) {
maximumSize.width = CGFLOAT_MAX;
} else {
maximumSize.height = CGFLOAT_MAX;
}
CGSize contentSize = [self sizeThatFitsMinimumSize:(CGSize)CGSizeZero maximumSize:maximumSize];
if (CGSizeEqualToSize(_previousContentSize, contentSize)) {
return;
}
_previousContentSize = contentSize;
_onContentSizeChange(@{
@"contentSize": @{
@"height": @(contentSize.height),
@"width": @(contentSize.width),
},
@"target": self.reactTag,
});
}
#pragma mark - RCTUIManagerObserver
- (void)uiManagerWillPerformMounting
{
if (YGNodeIsDirty(self.yogaNode)) {
return;
}
if (!_needsUpdateView) {
return;
}
_needsUpdateView = NO;
UIEdgeInsets borderInsets = self.borderAsInsets;
UIEdgeInsets paddingInsets = self.paddingAsInsets;
RCTTextAttributes *textAttributes = [self.textAttributes copy];
NSMutableAttributedString *attributedText =
[[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTextWithBaseTextAttributes:nil]];
// Removing all references to Shadow Views and tags to avoid unnececery retainning
// and problems with comparing the strings.
[attributedText removeAttribute:RCTBaseTextShadowViewEmbeddedShadowViewAttributeName
range:NSMakeRange(0, attributedText.length)];
[attributedText removeAttribute:RCTTextAttributesTagAttributeName
range:NSMakeRange(0, attributedText.length)];
if (self.text.length) {
NSAttributedString *propertyAttributedText =
[[NSAttributedString alloc] initWithString:self.text
attributes:self.textAttributes.effectiveTextAttributes];
[attributedText insertAttributedString:propertyAttributedText atIndex:0];
}
BOOL isAttributedTextChanged = NO;
if (![_previousAttributedText isEqualToAttributedString:attributedText]) {
// We have to follow `set prop` pattern:
// If the value has not changed, we must not notify the view about the change,
// otherwise we may break local (temporary) state of the text input.
isAttributedTextChanged = YES;
_previousAttributedText = [attributedText copy];
}
NSNumber *tag = self.reactTag;
[_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
RCTBaseTextInputView *baseTextInputView = (RCTBaseTextInputView *)viewRegistry[tag];
if (!baseTextInputView) {
return;
}
baseTextInputView.textAttributes = textAttributes;
baseTextInputView.reactBorderInsets = borderInsets;
baseTextInputView.reactPaddingInsets = paddingInsets;
if (isAttributedTextChanged) {
baseTextInputView.attributedText = attributedText;
}
}];
}
#pragma mark -
- (NSAttributedString *)measurableAttributedText
{
// Only for the very first render when we don't have `_localAttributedText`,
// we use value directly from the property and/or nested content.
NSAttributedString *attributedText =
_localAttributedText ?: [self attributedTextWithBaseTextAttributes:nil];
if (attributedText.length == 0) {
// It's impossible to measure empty attributed string because all attributes are
// assosiated with some characters, so no characters means no data.
// Placeholder also can represent the intrinsic size when it is visible.
NSString *text = self.placeholder;
if (!text.length) {
// Zero-width space
text = @"\u200B";
}
attributedText = [[NSAttributedString alloc] initWithString:text attributes:self.textAttributes.effectiveTextAttributes];
}
return attributedText;
}
- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize
{
NSAttributedString *attributedText = [self measurableAttributedText];
if (!_textStorage) {
_textContainer = [NSTextContainer new];
_textContainer.lineFragmentPadding = 0.0; // Note, the default value is 5.
_layoutManager = [NSLayoutManager new];
[_layoutManager addTextContainer:_textContainer];
_textStorage = [NSTextStorage new];
[_textStorage addLayoutManager:_layoutManager];
}
_textContainer.size = maximumSize;
_textContainer.maximumNumberOfLines = _maximumNumberOfLines;
[_textStorage replaceCharactersInRange:(NSRange){0, _textStorage.length}
withAttributedString:attributedText];
[_layoutManager ensureLayoutForTextContainer:_textContainer];
CGSize size = [_layoutManager usedRectForTextContainer:_textContainer].size;
return (CGSize){
MAX(minimumSize.width, MIN(RCTCeilPixelValue(size.width), maximumSize.width)),
MAX(minimumSize.height, MIN(RCTCeilPixelValue(size.height), maximumSize.height))
};
}
- (CGFloat)lastBaselineForSize:(CGSize)size
{
NSAttributedString *attributedText = [self measurableAttributedText];
__block CGFloat maximumDescender = 0.0;
[attributedText enumerateAttribute:NSFontAttributeName
inRange:NSMakeRange(0, attributedText.length)
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
usingBlock:
^(UIFont *font, NSRange range, __unused BOOL *stop) {
if (maximumDescender > font.descender) {
maximumDescender = font.descender;
}
}
];
return size.height + maximumDescender;
}
static YGSize RCTBaseTextInputShadowViewMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode)
{
RCTShadowView *shadowView = (__bridge RCTShadowView *)YGNodeGetContext(node);
CGSize minimumSize = CGSizeMake(0, 0);
CGSize maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
CGSize size = {
RCTCoreGraphicsFloatFromYogaFloat(width),
RCTCoreGraphicsFloatFromYogaFloat(height)
};
switch (widthMode) {
case YGMeasureModeUndefined:
break;
case YGMeasureModeExactly:
minimumSize.width = size.width;
maximumSize.width = size.width;
break;
case YGMeasureModeAtMost:
maximumSize.width = size.width;
break;
}
switch (heightMode) {
case YGMeasureModeUndefined:
break;
case YGMeasureModeExactly:
minimumSize.height = size.height;
maximumSize.height = size.height;
break;
case YGMeasureModeAtMost:
maximumSize.height = size.height;
break;
}
CGSize measuredSize = [shadowView sizeThatFitsMinimumSize:minimumSize maximumSize:maximumSize];
return (YGSize){
RCTYogaFloatFromCoreGraphicsFloat(measuredSize.width),
RCTYogaFloatFromCoreGraphicsFloat(measuredSize.height)
};
}
static float RCTTextInputShadowViewBaseline(YGNodeRef node, const float width, const float height)
{
RCTBaseTextInputShadowView *shadowTextView = (__bridge RCTBaseTextInputShadowView *)YGNodeGetContext(node);
CGSize size = (CGSize){
RCTCoreGraphicsFloatFromYogaFloat(width),
RCTCoreGraphicsFloatFromYogaFloat(height)
};
CGFloat lastBaseline = [shadowTextView lastBaselineForSize:size];
return RCTYogaFloatFromCoreGraphicsFloat(lastBaseline);
}
@end

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTView.h>
#import "RCTBackedTextInputDelegate.h"
#import "RCTBackedTextInputViewProtocol.h"
@class RCTBridge;
@class RCTEventDispatcher;
@class RCTTextAttributes;
@class RCTTextSelection;
NS_ASSUME_NONNULL_BEGIN
@interface RCTBaseTextInputView : RCTView <RCTBackedTextInputDelegate>
- (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithCoder:(NSCoder *)decoder NS_UNAVAILABLE;
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
@property (nonatomic, readonly) UIView<RCTBackedTextInputViewProtocol> *backedTextInputView;
@property (nonatomic, strong, nullable) RCTTextAttributes *textAttributes;
@property (nonatomic, assign) UIEdgeInsets reactPaddingInsets;
@property (nonatomic, assign) UIEdgeInsets reactBorderInsets;
@property (nonatomic, copy, nullable) RCTDirectEventBlock onContentSizeChange;
@property (nonatomic, copy, nullable) RCTDirectEventBlock onSelectionChange;
@property (nonatomic, copy, nullable) RCTDirectEventBlock onChange;
@property (nonatomic, copy, nullable) RCTDirectEventBlock onTextInput;
@property (nonatomic, copy, nullable) RCTDirectEventBlock onScroll;
@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;
@property (nonatomic, strong, nullable) NSNumber *maxLength;
@property (nonatomic, copy) NSAttributedString *attributedText;
@property (nonatomic, copy) NSString *inputAccessoryViewID;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,520 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextInputView.h"
#import <React/RCTAccessibilityManager.h>
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTUIManager.h>
#import <React/RCTUtils.h>
#import <React/UIView+React.h>
#import "RCTInputAccessoryView.h"
#import "RCTInputAccessoryViewContent.h"
#import "RCTTextAttributes.h"
#import "RCTTextSelection.h"
@implementation RCTBaseTextInputView {
__weak RCTBridge *_bridge;
__weak RCTEventDispatcher *_eventDispatcher;
BOOL _hasInputAccesoryView;
NSString *_Nullable _predictedText;
NSInteger _nativeEventCount;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
{
RCTAssertParam(bridge);
if (self = [super initWithFrame:CGRectZero]) {
_bridge = bridge;
_eventDispatcher = bridge.eventDispatcher;
}
return self;
}
RCT_NOT_IMPLEMENTED(- (instancetype)init)
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)decoder)
RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
- (UIView<RCTBackedTextInputViewProtocol> *)backedTextInputView
{
RCTAssert(NO, @"-[RCTBaseTextInputView backedTextInputView] must be implemented in subclass.");
return nil;
}
#pragma mark - RCTComponent
- (void)didUpdateReactSubviews
{
// Do nothing.
}
#pragma mark - Properties
- (void)setTextAttributes:(RCTTextAttributes *)textAttributes
{
_textAttributes = textAttributes;
[self enforceTextAttributesIfNeeded];
}
- (void)enforceTextAttributesIfNeeded
{
id<RCTBackedTextInputViewProtocol> backedTextInputView = self.backedTextInputView;
if (backedTextInputView.attributedText.string.length != 0) {
return;
}
backedTextInputView.font = _textAttributes.effectiveFont;
backedTextInputView.textColor = _textAttributes.effectiveForegroundColor;
backedTextInputView.textAlignment = _textAttributes.alignment;
}
- (void)setReactPaddingInsets:(UIEdgeInsets)reactPaddingInsets
{
_reactPaddingInsets = reactPaddingInsets;
// We apply `paddingInsets` as `backedTextInputView`'s `textContainerInset`.
self.backedTextInputView.textContainerInset = reactPaddingInsets;
[self setNeedsLayout];
}
- (void)setReactBorderInsets:(UIEdgeInsets)reactBorderInsets
{
_reactBorderInsets = reactBorderInsets;
// We apply `borderInsets` as `backedTextInputView` layout offset.
self.backedTextInputView.frame = UIEdgeInsetsInsetRect(self.bounds, reactBorderInsets);
[self setNeedsLayout];
}
- (NSAttributedString *)attributedText
{
return self.backedTextInputView.attributedText;
}
- (void)setAttributedText:(NSAttributedString *)attributedText
{
NSInteger eventLag = _nativeEventCount - _mostRecentEventCount;
if (eventLag == 0 && ![attributedText isEqualToAttributedString:self.backedTextInputView.attributedText]) {
UITextRange *selection = self.backedTextInputView.selectedTextRange;
NSInteger oldTextLength = self.backedTextInputView.attributedText.string.length;
self.backedTextInputView.attributedText = attributedText;
if (selection.empty) {
// Maintaining a cursor position relative to the end of the old text.
NSInteger offsetStart =
[self.backedTextInputView offsetFromPosition:self.backedTextInputView.beginningOfDocument
toPosition:selection.start];
NSInteger offsetFromEnd = oldTextLength - offsetStart;
NSInteger newOffset = attributedText.string.length - offsetFromEnd;
UITextPosition *position =
[self.backedTextInputView positionFromPosition:self.backedTextInputView.beginningOfDocument
offset:newOffset];
[self.backedTextInputView setSelectedTextRange:[self.backedTextInputView textRangeFromPosition:position toPosition:position]
notifyDelegate:YES];
}
[self updateLocalData];
} else if (eventLag > RCTTextUpdateLagWarningThreshold) {
RCTLogWarn(@"Native TextInput(%@) is %lld events ahead of JS - try to make your JS faster.", self.backedTextInputView.attributedText.string, (long long)eventLag);
}
}
- (RCTTextSelection *)selection
{
id<RCTBackedTextInputViewProtocol> backedTextInputView = self.backedTextInputView;
UITextRange *selectedTextRange = backedTextInputView.selectedTextRange;
return [[RCTTextSelection new] initWithStart:[backedTextInputView offsetFromPosition:backedTextInputView.beginningOfDocument toPosition:selectedTextRange.start]
end:[backedTextInputView offsetFromPosition:backedTextInputView.beginningOfDocument toPosition:selectedTextRange.end]];
}
- (void)setSelection:(RCTTextSelection *)selection
{
if (!selection) {
return;
}
id<RCTBackedTextInputViewProtocol> backedTextInputView = self.backedTextInputView;
UITextRange *previousSelectedTextRange = backedTextInputView.selectedTextRange;
UITextPosition *start = [backedTextInputView positionFromPosition:backedTextInputView.beginningOfDocument offset:selection.start];
UITextPosition *end = [backedTextInputView positionFromPosition:backedTextInputView.beginningOfDocument offset:selection.end];
UITextRange *selectedTextRange = [backedTextInputView textRangeFromPosition:start toPosition:end];
NSInteger eventLag = _nativeEventCount - _mostRecentEventCount;
if (eventLag == 0 && ![previousSelectedTextRange isEqual:selectedTextRange]) {
[backedTextInputView setSelectedTextRange:selectedTextRange notifyDelegate:NO];
} else if (eventLag > RCTTextUpdateLagWarningThreshold) {
RCTLogWarn(@"Native TextInput(%@) is %lld events ahead of JS - try to make your JS faster.", backedTextInputView.attributedText.string, (long long)eventLag);
}
}
#pragma mark - RCTBackedTextInputDelegate
- (BOOL)textInputShouldBeginEditing
{
return YES;
}
- (void)textInputDidBeginEditing
{
if (_clearTextOnFocus) {
self.backedTextInputView.attributedText = [NSAttributedString new];
}
if (_selectTextOnFocus) {
[self.backedTextInputView selectAll:nil];
}
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeFocus
reactTag:self.reactTag
text:self.backedTextInputView.attributedText.string
key:nil
eventCount:_nativeEventCount];
}
- (BOOL)textInputShouldEndEditing
{
return YES;
}
- (void)textInputDidEndEditing
{
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeEnd
reactTag:self.reactTag
text:self.backedTextInputView.attributedText.string
key:nil
eventCount:_nativeEventCount];
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeBlur
reactTag:self.reactTag
text:self.backedTextInputView.attributedText.string
key:nil
eventCount:_nativeEventCount];
}
- (BOOL)textInputShouldReturn
{
// We send `submit` event here, in `textInputShouldReturn`
// (not in `textInputDidReturn)`, because of semantic of the event:
// `onSubmitEditing` is called when "Submit" button
// (the blue key on onscreen keyboard) did pressed
// (no connection to any specific "submitting" process).
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeSubmit
reactTag:self.reactTag
text:self.backedTextInputView.attributedText.string
key:nil
eventCount:_nativeEventCount];
return _blurOnSubmit;
}
- (void)textInputDidReturn
{
// Does nothing.
}
- (BOOL)textInputShouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
id<RCTBackedTextInputViewProtocol> backedTextInputView = self.backedTextInputView;
if (!backedTextInputView.textWasPasted) {
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeKeyPress
reactTag:self.reactTag
text:nil
key:text
eventCount:_nativeEventCount];
}
if (_maxLength) {
NSUInteger allowedLength = _maxLength.integerValue - backedTextInputView.attributedText.string.length + range.length;
if (text.length > allowedLength) {
// If we typed/pasted more than one character, limit the text inputted.
if (text.length > 1) {
// Truncate the input string so the result is exactly maxLength
NSString *limitedString = [text substringToIndex:allowedLength];
NSMutableAttributedString *newAttributedText = [backedTextInputView.attributedText mutableCopy];
[newAttributedText replaceCharactersInRange:range withString:limitedString];
backedTextInputView.attributedText = newAttributedText;
_predictedText = newAttributedText.string;
// Collapse selection at end of insert to match normal paste behavior.
UITextPosition *insertEnd = [backedTextInputView positionFromPosition:backedTextInputView.beginningOfDocument
offset:(range.location + allowedLength)];
[backedTextInputView setSelectedTextRange:[backedTextInputView textRangeFromPosition:insertEnd toPosition:insertEnd]
notifyDelegate:YES];
[self textInputDidChange];
}
return NO;
}
}
if (range.location + range.length > _predictedText.length) {
// _predictedText got out of sync in a bad way, so let's just force sync it. Haven't been able to repro this, but
// it's causing a real crash here: #6523822
_predictedText = backedTextInputView.attributedText.string;
}
NSString *previousText = [_predictedText substringWithRange:range] ?: @"";
if (_predictedText) {
_predictedText = [_predictedText stringByReplacingCharactersInRange:range withString:text];
} else {
_predictedText = text;
}
if (_onTextInput) {
_onTextInput(@{
@"text": text,
@"previousText": previousText,
@"range": @{
@"start": @(range.location),
@"end": @(range.location + range.length)
},
@"eventCount": @(_nativeEventCount),
});
}
return YES;
}
- (void)textInputDidChange
{
[self updateLocalData];
id<RCTBackedTextInputViewProtocol> backedTextInputView = self.backedTextInputView;
// Detect when `backedTextInputView` updates happend that didn't invoke `shouldChangeTextInRange`
// (e.g. typing simplified chinese in pinyin will insert and remove spaces without
// calling shouldChangeTextInRange). This will cause JS to get out of sync so we
// update the mismatched range.
NSRange currentRange;
NSRange predictionRange;
if (findMismatch(backedTextInputView.attributedText.string, _predictedText, &currentRange, &predictionRange)) {
NSString *replacement = [backedTextInputView.attributedText.string substringWithRange:currentRange];
[self textInputShouldChangeTextInRange:predictionRange replacementText:replacement];
// JS will assume the selection changed based on the location of our shouldChangeTextInRange, so reset it.
[self textInputDidChangeSelection];
_predictedText = backedTextInputView.attributedText.string;
}
_nativeEventCount++;
if (_onChange) {
_onChange(@{
@"text": self.attributedText.string,
@"target": self.reactTag,
@"eventCount": @(_nativeEventCount),
});
}
}
- (void)textInputDidChangeSelection
{
if (!_onSelectionChange) {
return;
}
RCTTextSelection *selection = self.selection;
_onSelectionChange(@{
@"selection": @{
@"start": @(selection.start),
@"end": @(selection.end),
},
});
}
- (void)updateLocalData
{
[self enforceTextAttributesIfNeeded];
[_bridge.uiManager setLocalData:[self.backedTextInputView.attributedText copy]
forView:self];
}
#pragma mark - Layout (in UIKit terms, with all insets)
- (CGSize)intrinsicContentSize
{
CGSize size = self.backedTextInputView.intrinsicContentSize;
size.width += _reactBorderInsets.left + _reactBorderInsets.right;
size.height += _reactBorderInsets.top + _reactBorderInsets.bottom;
// Returning value DOES include border and padding insets.
return size;
}
- (CGSize)sizeThatFits:(CGSize)size
{
CGFloat compoundHorizontalBorderInset = _reactBorderInsets.left + _reactBorderInsets.right;
CGFloat compoundVerticalBorderInset = _reactBorderInsets.top + _reactBorderInsets.bottom;
size.width -= compoundHorizontalBorderInset;
size.height -= compoundVerticalBorderInset;
// Note: `paddingInsets` was already included in `backedTextInputView` size
// because it was applied as `textContainerInset`.
CGSize fittingSize = [self.backedTextInputView sizeThatFits:size];
fittingSize.width += compoundHorizontalBorderInset;
fittingSize.height += compoundVerticalBorderInset;
// Returning value DOES include border and padding insets.
return fittingSize;
}
#pragma mark - Accessibility
- (UIView *)reactAccessibilityElement
{
return self.backedTextInputView;
}
#pragma mark - Focus Control
- (void)reactFocus
{
[self.backedTextInputView reactFocus];
}
- (void)reactBlur
{
[self.backedTextInputView reactBlur];
}
- (void)didMoveToWindow
{
[self.backedTextInputView reactFocusIfNeeded];
}
#pragma mark - Custom Input Accessory View
- (void)didSetProps:(NSArray<NSString *> *)changedProps
{
if ([changedProps containsObject:@"inputAccessoryViewID"] && self.inputAccessoryViewID) {
[self setCustomInputAccessoryViewWithNativeID:self.inputAccessoryViewID];
} else if (!self.inputAccessoryViewID) {
[self setDefaultInputAccessoryView];
}
}
- (void)setCustomInputAccessoryViewWithNativeID:(NSString *)nativeID
{
#if !TARGET_OS_TV
__weak RCTBaseTextInputView *weakSelf = self;
[_bridge.uiManager rootViewForReactTag:self.reactTag withCompletion:^(UIView *rootView) {
RCTBaseTextInputView *strongSelf = weakSelf;
if (rootView) {
UIView *accessoryView = [strongSelf->_bridge.uiManager viewForNativeID:nativeID
withRootTag:rootView.reactTag];
if (accessoryView && [accessoryView isKindOfClass:[RCTInputAccessoryView class]]) {
strongSelf.backedTextInputView.inputAccessoryView = ((RCTInputAccessoryView *)accessoryView).content.inputAccessoryView;
[strongSelf reloadInputViewsIfNecessary];
}
}
}];
#endif /* !TARGET_OS_TV */
}
- (void)setDefaultInputAccessoryView
{
#if !TARGET_OS_TV
UIView<RCTBackedTextInputViewProtocol> *textInputView = self.backedTextInputView;
UIKeyboardType keyboardType = textInputView.keyboardType;
// These keyboard types (all are number pads) don't have a "Done" button by default,
// so we create an `inputAccessoryView` with this button for them.
BOOL shouldHaveInputAccesoryView =
(
keyboardType == UIKeyboardTypeNumberPad ||
keyboardType == UIKeyboardTypePhonePad ||
keyboardType == UIKeyboardTypeDecimalPad ||
keyboardType == UIKeyboardTypeASCIICapableNumberPad
) &&
textInputView.returnKeyType == UIReturnKeyDone;
if (_hasInputAccesoryView == shouldHaveInputAccesoryView) {
return;
}
_hasInputAccesoryView = shouldHaveInputAccesoryView;
if (shouldHaveInputAccesoryView) {
UIToolbar *toolbarView = [[UIToolbar alloc] init];
[toolbarView sizeToFit];
UIBarButtonItem *flexibleSpace =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
target:nil
action:nil];
UIBarButtonItem *doneButton =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:@selector(handleInputAccessoryDoneButton)];
toolbarView.items = @[flexibleSpace, doneButton];
textInputView.inputAccessoryView = toolbarView;
}
else {
textInputView.inputAccessoryView = nil;
}
[self reloadInputViewsIfNecessary];
#endif /* !TARGET_OS_TV */
}
- (void)reloadInputViewsIfNecessary
{
// We have to call `reloadInputViews` for focused text inputs to update an accessory view.
if (self.backedTextInputView.isFirstResponder) {
[self.backedTextInputView reloadInputViews];
}
}
- (void)handleInputAccessoryDoneButton
{
if ([self textInputShouldReturn]) {
[self.backedTextInputView endEditing:YES];
}
}
#pragma mark - Helpers
static BOOL findMismatch(NSString *first, NSString *second, NSRange *firstRange, NSRange *secondRange)
{
NSInteger firstMismatch = -1;
for (NSUInteger ii = 0; ii < MAX(first.length, second.length); ii++) {
if (ii >= first.length || ii >= second.length || [first characterAtIndex:ii] != [second characterAtIndex:ii]) {
firstMismatch = ii;
break;
}
}
if (firstMismatch == -1) {
return NO;
}
NSUInteger ii = second.length;
NSUInteger lastMismatch = first.length;
while (ii > firstMismatch && lastMismatch > firstMismatch) {
if ([first characterAtIndex:(lastMismatch - 1)] != [second characterAtIndex:(ii - 1)]) {
break;
}
ii--;
lastMismatch--;
}
*firstRange = NSMakeRange(firstMismatch, lastMismatch - firstMismatch);
*secondRange = NSMakeRange(firstMismatch, ii - firstMismatch);
return YES;
}
@end

View File

@@ -0,0 +1,12 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextViewManager.h"
@interface RCTBaseTextInputViewManager : RCTBaseTextViewManager
@end

View File

@@ -0,0 +1,124 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextInputViewManager.h"
#import <React/RCTAccessibilityManager.h>
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTFont.h>
#import <React/RCTShadowView+Layout.h>
#import <React/RCTShadowView.h>
#import <React/RCTUIManager.h>
#import <React/RCTUIManagerUtils.h>
#import <React/RCTUIManagerObserverCoordinator.h>
#import "RCTBaseTextInputShadowView.h"
#import "RCTBaseTextInputView.h"
#import "RCTConvert+Text.h"
@interface RCTBaseTextInputViewManager () <RCTUIManagerObserver>
@end
@implementation RCTBaseTextInputViewManager
{
NSHashTable<RCTBaseTextInputShadowView *> *_shadowViews;
}
RCT_EXPORT_MODULE()
#pragma mark - Unified <TextInput> properties
RCT_REMAP_VIEW_PROPERTY(autoCapitalize, backedTextInputView.autocapitalizationType, UITextAutocapitalizationType)
RCT_REMAP_VIEW_PROPERTY(autoCorrect, backedTextInputView.autocorrectionType, UITextAutocorrectionType)
RCT_REMAP_VIEW_PROPERTY(contextMenuHidden, backedTextInputView.contextMenuHidden, BOOL)
RCT_REMAP_VIEW_PROPERTY(editable, backedTextInputView.editable, BOOL)
RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, backedTextInputView.enablesReturnKeyAutomatically, BOOL)
RCT_REMAP_VIEW_PROPERTY(keyboardAppearance, backedTextInputView.keyboardAppearance, UIKeyboardAppearance)
RCT_REMAP_VIEW_PROPERTY(keyboardType, backedTextInputView.keyboardType, UIKeyboardType)
RCT_REMAP_VIEW_PROPERTY(placeholder, backedTextInputView.placeholder, NSString)
RCT_REMAP_VIEW_PROPERTY(placeholderTextColor, backedTextInputView.placeholderColor, UIColor)
RCT_REMAP_VIEW_PROPERTY(returnKeyType, backedTextInputView.returnKeyType, UIReturnKeyType)
RCT_REMAP_VIEW_PROPERTY(secureTextEntry, backedTextInputView.secureTextEntry, BOOL)
RCT_REMAP_VIEW_PROPERTY(selectionColor, backedTextInputView.tintColor, UIColor)
RCT_REMAP_VIEW_PROPERTY(spellCheck, backedTextInputView.spellCheckingType, UITextSpellCheckingType)
RCT_REMAP_VIEW_PROPERTY(caretHidden, backedTextInputView.caretHidden, BOOL)
RCT_REMAP_VIEW_PROPERTY(clearButtonMode, backedTextInputView.clearButtonMode, UITextFieldViewMode)
RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL)
RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL)
RCT_EXPORT_VIEW_PROPERTY(maxLength, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(selectTextOnFocus, BOOL)
RCT_EXPORT_VIEW_PROPERTY(selection, RCTTextSelection)
RCT_EXPORT_VIEW_PROPERTY(inputAccessoryViewID, NSString)
RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onTextInput, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(mostRecentEventCount, NSInteger)
RCT_EXPORT_SHADOW_PROPERTY(text, NSString)
RCT_EXPORT_SHADOW_PROPERTY(placeholder, NSString)
RCT_EXPORT_SHADOW_PROPERTY(onContentSizeChange, RCTBubblingEventBlock)
- (RCTShadowView *)shadowView
{
RCTBaseTextInputShadowView *shadowView = [[RCTBaseTextInputShadowView alloc] initWithBridge:self.bridge];
shadowView.textAttributes.fontSizeMultiplier = self.bridge.accessibilityManager.multiplier;
[_shadowViews addObject:shadowView];
return shadowView;
}
- (void)setBridge:(RCTBridge *)bridge
{
[super setBridge:bridge];
_shadowViews = [NSHashTable weakObjectsHashTable];
[bridge.uiManager.observerCoordinator addObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleDidUpdateMultiplierNotification)
name:RCTAccessibilityManagerDidUpdateMultiplierNotification
object:bridge.accessibilityManager];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - RCTUIManagerObserver
- (void)uiManagerWillPerformMounting:(__unused RCTUIManager *)uiManager
{
for (RCTBaseTextInputShadowView *shadowView in _shadowViews) {
[shadowView uiManagerWillPerformMounting];
}
}
#pragma mark - Font Size Multiplier
- (void)handleDidUpdateMultiplierNotification
{
CGFloat fontSizeMultiplier = self.bridge.accessibilityManager.multiplier;
NSHashTable<RCTBaseTextInputShadowView *> *shadowViews = _shadowViews;
RCTExecuteOnUIManagerQueue(^{
for (RCTBaseTextInputShadowView *shadowView in shadowViews) {
shadowView.textAttributes.fontSizeMultiplier = fontSizeMultiplier;
[shadowView dirtyLayout];
}
[self.bridge.uiManager setNeedsLayout];
});
}
@end

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
@class RCTBridge;
@class RCTInputAccessoryViewContent;
@interface RCTInputAccessoryView : UIView
- (instancetype)initWithBridge:(RCTBridge *)bridge;
@property (nonatomic, readonly, strong) RCTInputAccessoryViewContent *content;
@end

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTInputAccessoryView.h"
#import <React/RCTBridge.h>
#import <React/RCTTouchHandler.h>
#import <React/UIView+React.h>
#import "RCTInputAccessoryViewContent.h"
@implementation RCTInputAccessoryView
{
BOOL _contentShouldBeFirstResponder;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
{
if (self = [super init]) {
_content = [RCTInputAccessoryViewContent new];
RCTTouchHandler *const touchHandler = [[RCTTouchHandler alloc] initWithBridge:bridge];
[touchHandler attachToView:_content.inputAccessoryView];
[self addSubview:_content];
}
return self;
}
- (void)reactSetFrame:(CGRect)frame
{
[_content.inputAccessoryView setFrame:frame];
[_content.contentView setFrame:frame];
if (_contentShouldBeFirstResponder) {
_contentShouldBeFirstResponder = NO;
[_content becomeFirstResponder];
}
}
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)index
{
[super insertReactSubview:subview atIndex:index];
[_content insertReactSubview:subview atIndex:index];
}
- (void)removeReactSubview:(UIView *)subview
{
[super removeReactSubview:subview];
[_content removeReactSubview:subview];
}
- (void)didUpdateReactSubviews
{
// Do nothing, as subviews are managed by `insertReactSubview:atIndex:`
}
- (void)didSetProps:(NSArray<NSString *> *)changedProps
{
// If the accessory view is not linked to a text input via nativeID, assume it is
// a standalone component that should get focus whenever it is rendered
if (![changedProps containsObject:@"nativeID"] && !self.nativeID) {
_contentShouldBeFirstResponder = YES;
}
}
@end

View File

@@ -0,0 +1,14 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
@interface RCTInputAccessoryViewContent : UIView
@property (nonatomic, readwrite, retain) UIView *contentView;
@end

View File

@@ -0,0 +1,75 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTInputAccessoryViewContent.h"
#import <React/UIView+React.h>
@interface RCTInputAccessoryViewContent()
// Overriding `inputAccessoryView` to `readwrite`.
@property (nonatomic, readwrite, retain) UIView *inputAccessoryView;
@end
@implementation RCTInputAccessoryViewContent
- (BOOL)canBecomeFirstResponder
{
return true;
}
- (BOOL)becomeFirstResponder
{
const BOOL becameFirstResponder = [super becomeFirstResponder];
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
// Avoiding the home pill and notch (landscape mode) on iphoneX.
if (becameFirstResponder) {
if (@available(iOS 11.0, *)) {
[_contentView.bottomAnchor
constraintLessThanOrEqualToSystemSpacingBelowAnchor:_contentView.window.safeAreaLayoutGuide.bottomAnchor
multiplier:1.0f].active = YES;
[_contentView.leftAnchor
constraintLessThanOrEqualToSystemSpacingAfterAnchor:_contentView.window.safeAreaLayoutGuide.leftAnchor
multiplier:1.0f].active = YES;
[_contentView.rightAnchor
constraintLessThanOrEqualToSystemSpacingAfterAnchor:_contentView.window.safeAreaLayoutGuide.rightAnchor
multiplier:1.0f].active = YES;
}
}
#endif
return becameFirstResponder;
}
- (UIView *)inputAccessoryView
{
if (!_inputAccessoryView) {
_inputAccessoryView = [UIView new];
_contentView = [UIView new];
[_inputAccessoryView addSubview:_contentView];
}
return _inputAccessoryView;
}
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)index
{
[super insertReactSubview:subview atIndex:index];
[_contentView insertSubview:subview atIndex:index];
}
- (void)removeReactSubview:(UIView *)subview
{
[super removeReactSubview:subview];
[subview removeFromSuperview];
if ([[_inputAccessoryView subviews] count] == 0 && [self isFirstResponder]) {
[self resignFirstResponder];
}
}
@end

View File

@@ -0,0 +1,12 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTViewManager.h>
@interface RCTInputAccessoryViewManager : RCTViewManager
@end

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTInputAccessoryViewManager.h"
#import "RCTInputAccessoryView.h"
@implementation RCTInputAccessoryViewManager
RCT_EXPORT_MODULE()
+ (BOOL)requiresMainQueueSetup
{
return NO;
}
- (UIView *)view
{
return [[RCTInputAccessoryView alloc] initWithBridge:self.bridge];
}
RCT_REMAP_VIEW_PROPERTY(backgroundColor, content.inputAccessoryView.backgroundColor, UIColor)
@end

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTConvert.h>
/**
* Object containing information about a TextInput's selection.
*/
@interface RCTTextSelection : NSObject
@property (nonatomic, assign, readonly) NSInteger start;
@property (nonatomic, assign, readonly) NSInteger end;
- (instancetype)initWithStart:(NSInteger)start end:(NSInteger)end;
@end
@interface RCTConvert (RCTTextSelection)
+ (RCTTextSelection *)RCTTextSelection:(id)json;
@end

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTTextSelection.h"
@implementation RCTTextSelection
- (instancetype)initWithStart:(NSInteger)start end:(NSInteger)end
{
if (self = [super init]) {
_start = start;
_end = end;
}
return self;
}
@end
@implementation RCTConvert (RCTTextSelection)
+ (RCTTextSelection *)RCTTextSelection:(id)json
{
if ([json isKindOfClass:[NSDictionary class]]) {
NSInteger start = [self NSInteger:json[@"start"]];
NSInteger end = [self NSInteger:json[@"end"]];
return [[RCTTextSelection alloc] initWithStart:start end:end];
}
return nil;
}
@end

View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextInputView.h"
NS_ASSUME_NONNULL_BEGIN
@interface RCTSinglelineTextInputView : RCTBaseTextInputView
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,43 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTSinglelineTextInputView.h"
#import <React/RCTBridge.h>
#import "RCTUITextField.h"
@implementation RCTSinglelineTextInputView
{
RCTUITextField *_backedTextInputView;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
{
if (self = [super initWithBridge:bridge]) {
// `blurOnSubmit` defaults to `true` for <TextInput multiline={false}> by design.
self.blurOnSubmit = YES;
_backedTextInputView = [[RCTUITextField alloc] initWithFrame:self.bounds];
_backedTextInputView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_backedTextInputView.textInputDelegate = self;
[self addSubview:_backedTextInputView];
}
return self;
}
RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)coder)
- (id<RCTBackedTextInputViewProtocol>)backedTextInputView
{
return _backedTextInputView;
}
@end

View File

@@ -0,0 +1,16 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextInputViewManager.h"
NS_ASSUME_NONNULL_BEGIN
@interface RCTSinglelineTextInputViewManager : RCTBaseTextInputViewManager
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTSinglelineTextInputViewManager.h"
#import "RCTBaseTextInputShadowView.h"
#import "RCTSinglelineTextInputView.h"
@implementation RCTSinglelineTextInputViewManager
RCT_EXPORT_MODULE()
- (RCTShadowView *)shadowView
{
RCTBaseTextInputShadowView *shadowView =
(RCTBaseTextInputShadowView *)[super shadowView];
shadowView.maximumNumberOfLines = 1;
return shadowView;
}
- (UIView *)view
{
return [[RCTSinglelineTextInputView alloc] initWithBridge:self.bridge];
}
@end

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import "RCTBackedTextInputViewProtocol.h"
NS_ASSUME_NONNULL_BEGIN
/*
* Just regular UITextField... but much better!
*/
@interface RCTUITextField : UITextField <RCTBackedTextInputViewProtocol>
- (instancetype)initWithCoder:(NSCoder *)decoder NS_UNAVAILABLE;
@property (nonatomic, weak) id<RCTBackedTextInputDelegate> textInputDelegate;
@property (nonatomic, assign) BOOL caretHidden;
@property (nonatomic, assign) BOOL contextMenuHidden;
@property (nonatomic, assign, readonly) BOOL textWasPasted;
@property (nonatomic, strong, nullable) UIColor *placeholderColor;
@property (nonatomic, assign) UIEdgeInsets textContainerInset;
@property (nonatomic, assign, getter=isEditable) BOOL editable;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,174 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTUITextField.h"
#import <React/RCTUtils.h>
#import <React/UIView+React.h>
#import "RCTBackedTextInputDelegateAdapter.h"
@implementation RCTUITextField {
RCTBackedTextFieldDelegateAdapter *_textInputDelegateAdapter;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_textDidChange)
name:UITextFieldTextDidChangeNotification
object:self];
_textInputDelegateAdapter = [[RCTBackedTextFieldDelegateAdapter alloc] initWithTextField:self];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)_textDidChange
{
_textWasPasted = NO;
}
#pragma mark - Properties
- (void)setTextContainerInset:(UIEdgeInsets)textContainerInset
{
_textContainerInset = textContainerInset;
[self setNeedsLayout];
}
- (void)setPlaceholder:(NSString *)placeholder
{
[super setPlaceholder:placeholder];
[self _updatePlaceholder];
}
- (void)setPlaceholderColor:(UIColor *)placeholderColor
{
_placeholderColor = placeholderColor;
[self _updatePlaceholder];
}
- (void)_updatePlaceholder
{
if (self.placeholder == nil) {
return;
}
NSMutableDictionary *attributes = [NSMutableDictionary new];
if (_placeholderColor) {
[attributes setObject:_placeholderColor forKey:NSForegroundColorAttributeName];
}
self.attributedPlaceholder = [[NSAttributedString alloc] initWithString:self.placeholder
attributes:attributes];
}
- (BOOL)isEditable
{
return self.isEnabled;
}
- (void)setEditable:(BOOL)editable
{
self.enabled = editable;
}
#pragma mark - Context Menu
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if (_contextMenuHidden) {
return NO;
}
return [super canPerformAction:action withSender:sender];
}
#pragma mark - Caret Manipulation
- (CGRect)caretRectForPosition:(UITextPosition *)position
{
if (_caretHidden) {
return CGRectZero;
}
return [super caretRectForPosition:position];
}
#pragma mark - Positioning Overrides
- (CGRect)textRectForBounds:(CGRect)bounds
{
return UIEdgeInsetsInsetRect([super textRectForBounds:bounds], _textContainerInset);
}
- (CGRect)editingRectForBounds:(CGRect)bounds
{
return [self textRectForBounds:bounds];
}
#pragma mark - Overrides
- (void)setSelectedTextRange:(UITextRange *)selectedTextRange
{
[super setSelectedTextRange:selectedTextRange];
[_textInputDelegateAdapter selectedTextRangeWasSet];
}
- (void)setSelectedTextRange:(UITextRange *)selectedTextRange notifyDelegate:(BOOL)notifyDelegate
{
if (!notifyDelegate) {
// We have to notify an adapter that following selection change was initiated programmatically,
// so the adapter must not generate a notification for it.
[_textInputDelegateAdapter skipNextTextInputDidChangeSelectionEventWithTextRange:selectedTextRange];
}
[super setSelectedTextRange:selectedTextRange];
}
- (void)paste:(id)sender
{
[super paste:sender];
_textWasPasted = YES;
}
#pragma mark - Layout
- (CGSize)contentSize
{
// Returning size DOES contain `textContainerInset` (aka `padding`).
return self.intrinsicContentSize;
}
- (CGSize)intrinsicContentSize
{
// Note: `placeholder` defines intrinsic size for `<TextInput>`.
NSString *text = self.placeholder ?: @"";
CGSize size = [text sizeWithAttributes:@{NSFontAttributeName: self.font}];
size = CGSizeMake(RCTCeilPixelValue(size.width), RCTCeilPixelValue(size.height));
size.width += _textContainerInset.left + _textContainerInset.right;
size.height += _textContainerInset.top + _textContainerInset.bottom;
// Returning size DOES contain `textContainerInset` (aka `padding`).
return size;
}
- (CGSize)sizeThatFits:(CGSize)size
{
// All size values here contain `textContainerInset` (aka `padding`).
CGSize intrinsicSize = self.intrinsicContentSize;
return CGSizeMake(MIN(size.width, intrinsicSize.width), MIN(size.height, intrinsicSize.height));
}
@end

View File

@@ -0,0 +1,128 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule TextPropTypes
* @flow
* @format
*/
'use strict';
const ColorPropType = require('ColorPropType');
const EdgeInsetsPropType = require('EdgeInsetsPropType');
const PropTypes = require('prop-types');
const StyleSheetPropType = require('StyleSheetPropType');
const TextStylePropTypes = require('TextStylePropTypes');
const stylePropType = StyleSheetPropType(TextStylePropTypes);
module.exports = {
/**
* When `numberOfLines` is set, this prop defines how text will be
* truncated.
*
* See https://facebook.github.io/react-native/docs/text.html#ellipsizemode
*/
ellipsizeMode: PropTypes.oneOf(['head', 'middle', 'tail', 'clip']),
/**
* Used to truncate the text with an ellipsis.
*
* See https://facebook.github.io/react-native/docs/text.html#numberoflines
*/
numberOfLines: PropTypes.number,
/**
* Set text break strategy on Android.
*
* See https://facebook.github.io/react-native/docs/text.html#textbreakstrategy
*/
textBreakStrategy: PropTypes.oneOf(['simple', 'highQuality', 'balanced']),
/**
* Invoked on mount and layout changes.
*
* See https://facebook.github.io/react-native/docs/text.html#onlayout
*/
onLayout: PropTypes.func,
/**
* This function is called on press.
*
* See https://facebook.github.io/react-native/docs/text.html#onpress
*/
onPress: PropTypes.func,
/**
* This function is called on long press.
*
* See https://facebook.github.io/react-native/docs/text.html#onlongpress
*/
onLongPress: PropTypes.func,
/**
* Defines how far your touch may move off of the button, before
* deactivating the button.
*
* See https://facebook.github.io/react-native/docs/text.html#pressretentionoffset
*/
pressRetentionOffset: EdgeInsetsPropType,
/**
* Lets the user select text.
*
* See https://facebook.github.io/react-native/docs/text.html#selectable
*/
selectable: PropTypes.bool,
/**
* The highlight color of the text.
*
* See https://facebook.github.io/react-native/docs/text.html#selectioncolor
*/
selectionColor: ColorPropType,
/**
* When `true`, no visual change is made when text is pressed down.
*
* See https://facebook.github.io/react-native/docs/text.html#supperhighlighting
*/
suppressHighlighting: PropTypes.bool,
style: stylePropType,
/**
* Used to locate this view in end-to-end tests.
*
* See https://facebook.github.io/react-native/docs/text.html#testid
*/
testID: PropTypes.string,
/**
* Used to locate this view from native code.
*
* See https://facebook.github.io/react-native/docs/text.html#nativeid
*/
nativeID: PropTypes.string,
/**
* Whether fonts should scale to respect Text Size accessibility settings.
*
* See https://facebook.github.io/react-native/docs/text.html#allowfontscaling
*/
allowFontScaling: PropTypes.bool,
/**
* Indicates whether the view is an accessibility element.
*
* See https://facebook.github.io/react-native/docs/text.html#accessible
*/
accessible: PropTypes.bool,
/**
* Whether font should be scaled down automatically.
*
* See https://facebook.github.io/react-native/docs/text.html#adjustsfontsizetofit
*/
adjustsFontSizeToFit: PropTypes.bool,
/**
* Smallest possible scale a font can reach.
*
* See https://facebook.github.io/react-native/docs/text.html#minimumfontscale
*/
minimumFontScale: PropTypes.number,
/**
* Specifies the disabled state of the text view for testing purposes.
*
* See https://facebook.github.io/react-native/docs/text.html#disabled
*/
disabled: PropTypes.bool,
};

59
node_modules/react-native/Libraries/Text/TextProps.js generated vendored Normal file
View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule TextProps
* @flow
* @format
*/
'use strict';
import type {Node} from 'react';
import type {LayoutEvent, PressEvent} from 'CoreEventTypes';
import type {DangerouslyImpreciseStyleProp} from 'StyleSheet';
type PressRetentionOffset = {
top: number,
left: number,
bottom: number,
right: number,
};
/**
* @see https://facebook.github.io/react-native/docs/text.html#reference
*/
export type TextProps = $ReadOnly<{
accessible?: ?boolean,
allowFontScaling?: ?boolean,
children?: Node,
ellipsizeMode?: 'clip' | 'head' | 'middle' | 'tail',
nativeID?: string,
numberOfLines?: ?number,
onLayout?: ?(event: LayoutEvent) => mixed,
onLongPress?: ?(event: PressEvent) => mixed,
onPress?: ?(event: PressEvent) => mixed,
onResponderGrant?: ?Function,
onResponderMove?: ?Function,
onResponderRelease?: ?Function,
onResponderTerminate?: ?Function,
onResponderTerminationRequest?: ?Function,
onStartShouldSetResponder?: ?Function,
pressRetentionOffset?: ?PressRetentionOffset,
selectable?: ?boolean,
style?: ?DangerouslyImpreciseStyleProp,
testID?: string,
// Android Only
disabled?: ?boolean,
selectionColor?: ?string,
textBreakStrategy?: 'balanced' | 'highQuality' | 'simple',
// iOS Only
adjustsFontSizeToFit?: ?boolean,
minimumFontScale?: ?number,
suppressHighlighting?: ?boolean,
}>;

View File

@@ -0,0 +1,95 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule TextStylePropTypes
* @flow
*/
'use strict';
const ColorPropType = require('ColorPropType');
const ReactPropTypes = require('prop-types');
const ViewStylePropTypes = require('ViewStylePropTypes');
const TextStylePropTypes = {
...ViewStylePropTypes,
color: ColorPropType,
fontFamily: ReactPropTypes.string,
fontSize: ReactPropTypes.number,
fontStyle: ReactPropTypes.oneOf(['normal', 'italic']),
/**
* Specifies font weight. The values 'normal' and 'bold' are supported for
* most fonts. Not all fonts have a variant for each of the numeric values,
* in that case the closest one is chosen.
*/
fontWeight: ReactPropTypes.oneOf(
['normal' /*default*/, 'bold',
'100', '200', '300', '400', '500', '600', '700', '800', '900']
),
/**
* @platform ios
*/
fontVariant: ReactPropTypes.arrayOf(
ReactPropTypes.oneOf([
'small-caps',
'oldstyle-nums',
'lining-nums',
'tabular-nums',
'proportional-nums',
])
),
textShadowOffset: ReactPropTypes.shape(
{width: ReactPropTypes.number, height: ReactPropTypes.number}
),
textShadowRadius: ReactPropTypes.number,
textShadowColor: ColorPropType,
/**
* @platform ios
*/
letterSpacing: ReactPropTypes.number,
lineHeight: ReactPropTypes.number,
/**
* Specifies text alignment. The value 'justify' is only supported on iOS and
* fallbacks to `left` on Android.
*/
textAlign: ReactPropTypes.oneOf(
['auto' /*default*/, 'left', 'right', 'center', 'justify']
),
/**
* @platform android
*/
textAlignVertical: ReactPropTypes.oneOf(
['auto' /*default*/, 'top', 'bottom', 'center']
),
/**
* Set to `false` to remove extra font padding intended to make space for certain ascenders / descenders.
* With some fonts, this padding can make text look slightly misaligned when centered vertically.
* For best results also set `textAlignVertical` to `center`. Default is true.
* @platform android
*/
includeFontPadding: ReactPropTypes.bool,
textDecorationLine: ReactPropTypes.oneOf(
['none' /*default*/, 'underline', 'line-through', 'underline line-through']
),
/**
* @platform ios
*/
textDecorationStyle: ReactPropTypes.oneOf(
['solid' /*default*/, 'double', 'dotted','dashed']
),
/**
* @platform ios
*/
textDecorationColor: ColorPropType,
/**
* @platform ios
*/
writingDirection: ReactPropTypes.oneOf(
['auto' /*default*/, 'ltr', 'rtl']
),
};
module.exports = TextStylePropTypes;

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @providesModule TextUpdateTest
* @flow
*/
'use strict';
var React = require('react');
var createReactClass = require('create-react-class');
var ReactNative = require('react-native');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
* found when Flow v0.54 was deployed. To see the error delete this comment and
* run Flow. */
var TimerMixin = require('react-timer-mixin');
var {
NativeModules,
StyleSheet,
Text,
} = ReactNative;
var TestManager = NativeModules.TestManager || NativeModules.SnapshotTestManager;
var TextUpdateTest = createReactClass({
displayName: 'TextUpdateTest',
mixins: [TimerMixin],
getInitialState: function() {
return {seeMore: true};
},
componentDidMount: function() {
this.requestAnimationFrame(
() => this.setState({seeMore: false}, () => {
TestManager.markTestCompleted();
})
);
},
render: function() {
return (
<Text
style={styles.container}
onPress={() => this.setState({seeMore: !this.state.seeMore})}>
<Text>Tap to see more (bugs)...</Text>
{this.state.seeMore && 'raw text'}
</Text>
);
},
});
var styles = StyleSheet.create({
container: {
margin: 10,
marginTop: 100,
},
});
module.exports = TextUpdateTest;

View File

@@ -0,0 +1,12 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextShadowView.h"
@interface RCTVirtualTextShadowView : RCTBaseTextShadowView
@end

View File

@@ -0,0 +1,73 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTVirtualTextShadowView.h"
#import <React/RCTShadowView+Layout.h>
#import <yoga/Yoga.h>
#import "RCTRawTextShadowView.h"
@implementation RCTVirtualTextShadowView {
BOOL _isLayoutDirty;
}
#pragma mark - Life Cycle
- (void)insertReactSubview:(RCTShadowView *)subview atIndex:(NSInteger)index
{
[super insertReactSubview:subview atIndex:index];
[self dirtyLayout];
if (![subview isKindOfClass:[RCTVirtualTextShadowView class]]) {
YGNodeSetDirtiedFunc(subview.yogaNode, RCTVirtualTextShadowViewYogaNodeDirtied);
}
}
- (void)removeReactSubview:(RCTShadowView *)subview
{
if (![subview isKindOfClass:[RCTVirtualTextShadowView class]]) {
YGNodeSetDirtiedFunc(subview.yogaNode, NULL);
}
[self dirtyLayout];
[super removeReactSubview:subview];
}
#pragma mark - Layout
- (void)dirtyLayout
{
[super dirtyLayout];
if (_isLayoutDirty) {
return;
}
_isLayoutDirty = YES;
[self.superview dirtyLayout];
}
- (void)clearLayout
{
_isLayoutDirty = NO;
}
static void RCTVirtualTextShadowViewYogaNodeDirtied(YGNodeRef node)
{
RCTShadowView *shadowView = (__bridge RCTShadowView *)YGNodeGetContext(node);
RCTVirtualTextShadowView *virtualTextShadowView =
(RCTVirtualTextShadowView *)shadowView.reactSuperview;
[virtualTextShadowView dirtyLayout];
}
@end

View File

@@ -0,0 +1,12 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBaseTextViewManager.h"
@interface RCTVirtualTextViewManager : RCTBaseTextViewManager
@end

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTVirtualTextViewManager.h"
#import "RCTVirtualTextShadowView.h"
@implementation RCTVirtualTextViewManager
RCT_EXPORT_MODULE(RCTVirtualText)
- (UIView *)view
{
return [UIView new];
}
- (RCTShadowView *)shadowView
{
return [RCTVirtualTextShadowView new];
}
@end