This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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/RCTViewComponentView.h>
NS_ASSUME_NONNULL_BEGIN
/**
* UIView class for <TextInput> component.
*/
@interface RCTTextInputComponentView : RCTViewComponentView
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,439 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTTextInputComponentView.h"
#import <react/components/iostextinput/TextInputComponentDescriptor.h>
#import <react/graphics/Geometry.h>
#import <react/textlayoutmanager/RCTAttributedTextUtils.h>
#import <react/textlayoutmanager/TextLayoutManager.h>
#import <React/RCTBackedTextInputViewProtocol.h>
#import <React/RCTUITextField.h>
#import <React/RCTUITextView.h>
#import "RCTConversions.h"
#import "RCTTextInputNativeCommands.h"
#import "RCTTextInputUtils.h"
using namespace facebook::react;
@interface RCTTextInputComponentView () <RCTBackedTextInputDelegate, RCTTextInputViewProtocol>
@end
@implementation RCTTextInputComponentView {
TextInputShadowNode::ConcreteState::Shared _state;
UIView<RCTBackedTextInputViewProtocol> *_backedTextInputView;
NSUInteger _mostRecentEventCount;
NSAttributedString *_lastStringStateWasUpdatedWith;
/*
* UIKit uses either UITextField or UITextView as its UIKit element for <TextInput>. UITextField is for single line
* entry, UITextView is for multiline entry. There is a problem with order of events when user types a character. In
* UITextField (single line text entry), typing a character first triggers `onChange` event and then
* onSelectionChange. In UITextView (multi line text entry), typing a character first triggers `onSelectionChange` and
* then onChange. JavaScript depends on `onChange` to be called before `onSelectionChange`. This flag keeps state so
* if UITextView is backing text input view, inside `-[RCTTextInputComponentView textInputDidChangeSelection]` we make
* sure to call `onChange` before `onSelectionChange` and ignore next `-[RCTTextInputComponentView
* textInputDidChange]` call.
*/
BOOL _ignoreNextTextInputCall;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<TextInputProps const>();
_props = defaultProps;
auto &props = *defaultProps;
_backedTextInputView = props.traits.multiline ? [[RCTUITextView alloc] init] : [[RCTUITextField alloc] init];
_backedTextInputView.frame = self.bounds;
_backedTextInputView.textInputDelegate = self;
_ignoreNextTextInputCall = NO;
[self addSubview:_backedTextInputView];
}
return self;
}
#pragma mark - RCTComponentViewProtocol
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return concreteComponentDescriptorProvider<TextInputComponentDescriptor>();
}
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
{
auto const &oldTextInputProps = *std::static_pointer_cast<TextInputProps const>(_props);
auto const &newTextInputProps = *std::static_pointer_cast<TextInputProps const>(props);
// Traits:
if (newTextInputProps.traits.multiline != oldTextInputProps.traits.multiline) {
[self _setMultiline:newTextInputProps.traits.multiline];
}
if (newTextInputProps.traits.autocapitalizationType != oldTextInputProps.traits.autocapitalizationType) {
_backedTextInputView.autocapitalizationType =
RCTUITextAutocapitalizationTypeFromAutocapitalizationType(newTextInputProps.traits.autocapitalizationType);
}
if (newTextInputProps.traits.autoCorrect != oldTextInputProps.traits.autoCorrect) {
_backedTextInputView.autocorrectionType =
RCTUITextAutocorrectionTypeFromOptionalBool(newTextInputProps.traits.autoCorrect);
}
if (newTextInputProps.traits.contextMenuHidden != oldTextInputProps.traits.contextMenuHidden) {
_backedTextInputView.contextMenuHidden = newTextInputProps.traits.contextMenuHidden;
}
if (newTextInputProps.traits.editable != oldTextInputProps.traits.editable) {
_backedTextInputView.editable = newTextInputProps.traits.editable;
}
if (newTextInputProps.traits.enablesReturnKeyAutomatically !=
oldTextInputProps.traits.enablesReturnKeyAutomatically) {
_backedTextInputView.enablesReturnKeyAutomatically = newTextInputProps.traits.enablesReturnKeyAutomatically;
}
if (newTextInputProps.traits.keyboardAppearance != oldTextInputProps.traits.keyboardAppearance) {
_backedTextInputView.keyboardAppearance =
RCTUIKeyboardAppearanceFromKeyboardAppearance(newTextInputProps.traits.keyboardAppearance);
}
if (newTextInputProps.traits.spellCheck != oldTextInputProps.traits.spellCheck) {
_backedTextInputView.spellCheckingType =
RCTUITextSpellCheckingTypeFromOptionalBool(newTextInputProps.traits.spellCheck);
}
if (newTextInputProps.traits.caretHidden != oldTextInputProps.traits.caretHidden) {
_backedTextInputView.caretHidden = newTextInputProps.traits.caretHidden;
}
if (newTextInputProps.traits.clearButtonMode != oldTextInputProps.traits.clearButtonMode) {
_backedTextInputView.clearButtonMode =
RCTUITextFieldViewModeFromTextInputAccessoryVisibilityMode(newTextInputProps.traits.clearButtonMode);
}
if (newTextInputProps.traits.scrollEnabled != oldTextInputProps.traits.scrollEnabled) {
_backedTextInputView.scrollEnabled = newTextInputProps.traits.scrollEnabled;
}
if (newTextInputProps.traits.secureTextEntry != oldTextInputProps.traits.secureTextEntry) {
_backedTextInputView.secureTextEntry = newTextInputProps.traits.secureTextEntry;
}
if (newTextInputProps.traits.keyboardType != oldTextInputProps.traits.keyboardType) {
_backedTextInputView.keyboardType = RCTUIKeyboardTypeFromKeyboardType(newTextInputProps.traits.keyboardType);
}
if (newTextInputProps.traits.returnKeyType != oldTextInputProps.traits.returnKeyType) {
_backedTextInputView.returnKeyType = RCTUIReturnKeyTypeFromReturnKeyType(newTextInputProps.traits.returnKeyType);
}
if (newTextInputProps.traits.textContentType != oldTextInputProps.traits.textContentType) {
if (@available(iOS 10.0, *)) {
_backedTextInputView.textContentType = RCTUITextContentTypeFromString(newTextInputProps.traits.textContentType);
}
}
if (newTextInputProps.traits.passwordRules != oldTextInputProps.traits.passwordRules) {
if (@available(iOS 12.0, *)) {
_backedTextInputView.passwordRules =
RCTUITextInputPasswordRulesFromString(newTextInputProps.traits.passwordRules);
}
}
// Traits `blurOnSubmit`, `clearTextOnFocus`, and `selectTextOnFocus` were omitted intentially here
// because they are being checked on-demand.
// Other props:
if (newTextInputProps.placeholder != oldTextInputProps.placeholder) {
_backedTextInputView.placeholder = RCTNSStringFromString(newTextInputProps.placeholder);
}
if (newTextInputProps.textAttributes != oldTextInputProps.textAttributes) {
_backedTextInputView.defaultTextAttributes =
RCTNSTextAttributesFromTextAttributes(newTextInputProps.getEffectiveTextAttributes());
}
if (newTextInputProps.selectionColor != oldTextInputProps.selectionColor) {
_backedTextInputView.tintColor = RCTUIColorFromSharedColor(newTextInputProps.selectionColor);
}
[super updateProps:props oldProps:oldProps];
}
- (void)updateState:(State::Shared const &)state oldState:(State::Shared const &)oldState
{
_state = std::static_pointer_cast<TextInputShadowNode::ConcreteState const>(state);
if (!_state) {
assert(false && "State is `null` for <TextInput> component.");
_backedTextInputView.attributedText = nil;
return;
}
if (_mostRecentEventCount == _state->getData().mostRecentEventCount) {
auto data = _state->getData();
[self _setAttributedString:RCTNSAttributedStringFromAttributedStringBox(data.attributedStringBox)];
}
}
- (void)updateLayoutMetrics:(LayoutMetrics const &)layoutMetrics
oldLayoutMetrics:(LayoutMetrics const &)oldLayoutMetrics
{
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
_backedTextInputView.frame =
UIEdgeInsetsInsetRect(self.bounds, RCTUIEdgeInsetsFromEdgeInsets(layoutMetrics.borderWidth));
_backedTextInputView.textContainerInset =
RCTUIEdgeInsetsFromEdgeInsets(layoutMetrics.contentInsets - layoutMetrics.borderWidth);
}
- (void)_setAttributedString:(NSAttributedString *)attributedString
{
UITextRange *selectedRange = [_backedTextInputView selectedTextRange];
_backedTextInputView.attributedText = attributedString;
// Calling `[_backedTextInputView setAttributedText]` results
// in `textInputDidChangeSelection` being called but not `textInputDidChange`.
// For `_ignoreNextTextInputCall` to have correct value, these calls
// need to be balanced, that's why we manually set the flag here.
_ignoreNextTextInputCall = NO;
if (_lastStringStateWasUpdatedWith.length == attributedString.length) {
// Calling `[_backedTextInputView setAttributedText]` moves caret
// to the end of text input field. This cancels any selection as well
// as position in the text input field. In case the length of string
// doesn't change, selection and caret position is maintained.
[_backedTextInputView setSelectedTextRange:selectedRange notifyDelegate:NO];
}
_lastStringStateWasUpdatedWith = attributedString;
}
- (void)prepareForRecycle
{
[super prepareForRecycle];
_backedTextInputView.attributedText = [[NSAttributedString alloc] init];
_mostRecentEventCount = 0;
_state.reset();
_lastStringStateWasUpdatedWith = nil;
_ignoreNextTextInputCall = NO;
}
#pragma mark - RCTComponentViewProtocol
- (void)_setMultiline:(BOOL)multiline
{
[_backedTextInputView removeFromSuperview];
UIView<RCTBackedTextInputViewProtocol> *backedTextInputView =
multiline ? [[RCTUITextView alloc] init] : [[RCTUITextField alloc] init];
backedTextInputView.frame = _backedTextInputView.frame;
RCTCopyBackedTextInput(_backedTextInputView, backedTextInputView);
_backedTextInputView = backedTextInputView;
[self addSubview:_backedTextInputView];
}
#pragma mark - RCTBackedTextInputDelegate
- (BOOL)textInputShouldBeginEditing
{
return YES;
}
- (void)textInputDidBeginEditing
{
auto const &props = *std::static_pointer_cast<TextInputProps const>(_props);
if (props.traits.clearTextOnFocus) {
_backedTextInputView.attributedText = [NSAttributedString new];
[self textInputDidChange];
}
if (props.traits.selectTextOnFocus) {
[_backedTextInputView selectAll:nil];
[self textInputDidChangeSelection];
}
if (_eventEmitter) {
std::static_pointer_cast<TextInputEventEmitter const>(_eventEmitter)->onFocus([self _textInputMetrics]);
}
}
- (BOOL)textInputShouldEndEditing
{
return YES;
}
- (void)textInputDidEndEditing
{
if (_eventEmitter) {
std::static_pointer_cast<TextInputEventEmitter const>(_eventEmitter)->onEndEditing([self _textInputMetrics]);
std::static_pointer_cast<TextInputEventEmitter const>(_eventEmitter)->onBlur([self _textInputMetrics]);
}
}
- (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).
if (_eventEmitter) {
std::static_pointer_cast<TextInputEventEmitter const>(_eventEmitter)->onSubmitEditing([self _textInputMetrics]);
}
auto const &props = *std::static_pointer_cast<TextInputProps const>(_props);
return props.traits.blurOnSubmit;
}
- (void)textInputDidReturn
{
// Does nothing.
}
- (NSString *)textInputShouldChangeText:(NSString *)text inRange:(NSRange)range
{
if (!_backedTextInputView.textWasPasted) {
if (_eventEmitter) {
KeyPressMetrics keyPressMetrics;
keyPressMetrics.text = RCTStringFromNSString(text);
keyPressMetrics.eventCount = _mostRecentEventCount;
std::static_pointer_cast<TextInputEventEmitter const>(_eventEmitter)->onKeyPress(keyPressMetrics);
}
}
auto const &props = *std::static_pointer_cast<TextInputProps const>(_props);
if (props.maxLength) {
NSInteger allowedLength = props.maxLength - _backedTextInputView.attributedText.string.length + range.length;
if (allowedLength <= 0) {
return nil;
}
return allowedLength > text.length ? text : [text substringToIndex:allowedLength];
}
return text;
}
- (BOOL)textInputShouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
return YES;
}
- (void)textInputDidChange
{
if (_ignoreNextTextInputCall) {
_ignoreNextTextInputCall = NO;
return;
}
[self _updateState];
if (_eventEmitter) {
std::static_pointer_cast<TextInputEventEmitter const>(_eventEmitter)->onChange([self _textInputMetrics]);
}
}
- (void)textInputDidChangeSelection
{
auto const &props = *std::static_pointer_cast<TextInputProps const>(_props);
if (props.traits.multiline && ![_lastStringStateWasUpdatedWith isEqual:_backedTextInputView.attributedText]) {
[self textInputDidChange];
_ignoreNextTextInputCall = YES;
}
if (_eventEmitter) {
std::static_pointer_cast<TextInputEventEmitter const>(_eventEmitter)->onSelectionChange([self _textInputMetrics]);
}
}
#pragma mark - Other
- (TextInputMetrics)_textInputMetrics
{
TextInputMetrics metrics;
metrics.text = RCTStringFromNSString(_backedTextInputView.attributedText.string);
metrics.selectionRange = [self _selectionRange];
metrics.eventCount = _mostRecentEventCount;
return metrics;
}
- (void)_updateState
{
NSAttributedString *attributedString = _backedTextInputView.attributedText;
if (!_state) {
return;
}
auto data = _state->getData();
_lastStringStateWasUpdatedWith = attributedString;
data.attributedStringBox = RCTAttributedStringBoxFromNSAttributedString(attributedString);
_mostRecentEventCount += 1;
data.mostRecentEventCount = _mostRecentEventCount;
_state->updateState(std::move(data));
}
- (AttributedString::Range)_selectionRange
{
UITextRange *selectedTextRange = _backedTextInputView.selectedTextRange;
NSInteger start = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
toPosition:selectedTextRange.start];
NSInteger end = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
toPosition:selectedTextRange.end];
return AttributedString::Range{(int)start, (int)(end - start)};
}
#pragma mark - Native Commands
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
{
RCTTextInputHandleCommand(self, commandName, args);
}
- (void)focus
{
[_backedTextInputView becomeFirstResponder];
}
- (void)blur
{
[_backedTextInputView resignFirstResponder];
}
- (void)setTextAndSelection:(NSInteger)eventCount
value:(NSString *__nullable)value
start:(NSInteger)start
end:(NSInteger)end
{
if (_mostRecentEventCount != eventCount) {
return;
}
if (value) {
NSMutableAttributedString *mutableString =
[[NSMutableAttributedString alloc] initWithAttributedString:_backedTextInputView.attributedText];
[mutableString replaceCharactersInRange:NSMakeRange(0, _backedTextInputView.attributedText.length)
withString:value];
[self _setAttributedString:mutableString];
[self _updateState];
}
UITextPosition *startPosition = [_backedTextInputView positionFromPosition:_backedTextInputView.beginningOfDocument
offset:start];
UITextPosition *endPosition = [_backedTextInputView positionFromPosition:_backedTextInputView.beginningOfDocument
offset:end];
if (startPosition && endPosition) {
UITextRange *range = [_backedTextInputView textRangeFromPosition:startPosition toPosition:endPosition];
[_backedTextInputView setSelectedTextRange:range notifyDelegate:NO];
}
}
@end

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTDefines.h>
#import <React/RCTLog.h>
NS_ASSUME_NONNULL_BEGIN
@protocol RCTTextInputViewProtocol <NSObject>
- (void)focus;
- (void)blur;
- (void)setTextAndSelection:(NSInteger)eventCount
value:(NSString *__nullable)value
start:(NSInteger)start
end:(NSInteger)end;
@end
RCT_EXTERN inline void
RCTTextInputHandleCommand(id<RCTTextInputViewProtocol> componentView, NSString const *commandName, NSArray const *args)
{
if ([commandName isEqualToString:@"focus"]) {
#if RCT_DEBUG
if ([args count] != 0) {
RCTLogError(
@"%@ command %@ received %d arguments, expected %d.", @"TextInput", commandName, (int)[args count], 0);
return;
}
#endif
[componentView focus];
return;
}
if ([commandName isEqualToString:@"blur"]) {
#if RCT_DEBUG
if ([args count] != 0) {
RCTLogError(
@"%@ command %@ received %d arguments, expected %d.", @"TextInput", commandName, (int)[args count], 0);
return;
}
#endif
[componentView blur];
return;
}
if ([commandName isEqualToString:@"setTextAndSelection"]) {
#if RCT_DEBUG
if ([args count] != 4) {
RCTLogError(
@"%@ command %@ received %d arguments, expected %d.", @"TextInput", commandName, (int)[args count], 4);
return;
}
#endif
NSObject *arg0 = args[0];
#if RCT_DEBUG
if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSNumber class], @"number", @"TextInput", commandName, @"1st")) {
return;
}
#endif
NSInteger eventCount = [(NSNumber *)arg0 intValue];
NSObject *arg1 = args[1];
#if RCT_DEBUG
if (![arg1 isKindOfClass:[NSNull class]] &&
!RCTValidateTypeOfViewCommandArgument(arg1, [NSString class], @"string", @"TextInput", commandName, @"2nd")) {
return;
}
#endif
NSString *value = [arg1 isKindOfClass:[NSNull class]] ? nil : (NSString *)arg1;
NSObject *arg2 = args[2];
#if RCT_DEBUG
if (!RCTValidateTypeOfViewCommandArgument(arg2, [NSNumber class], @"number", @"TextInput", commandName, @"3rd")) {
return;
}
#endif
NSInteger start = [(NSNumber *)arg2 intValue];
NSObject *arg3 = args[3];
#if RCT_DEBUG
if (!RCTValidateTypeOfViewCommandArgument(arg3, [NSNumber class], @"number", @"TextInput", commandName, @"4th")) {
return;
}
#endif
NSInteger end = [(NSNumber *)arg3 intValue];
[componentView setTextAndSelection:eventCount value:value start:start end:end];
return;
}
#if RCT_DEBUG
RCTLogError(@"%@ received command %@, which is not a supported command.", @"TextInput", commandName);
#endif
}
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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/RCTBackedTextInputViewProtocol.h>
#import <better/optional.h>
#import <react/components/iostextinput/primitives.h>
NS_ASSUME_NONNULL_BEGIN
void RCTCopyBackedTextInput(
UIView<RCTBackedTextInputViewProtocol> *fromTextInput,
UIView<RCTBackedTextInputViewProtocol> *toTextInput);
UITextAutocorrectionType RCTUITextAutocorrectionTypeFromOptionalBool(facebook::better::optional<bool> autoCorrect);
UITextAutocapitalizationType RCTUITextAutocapitalizationTypeFromAutocapitalizationType(
facebook::react::AutocapitalizationType autocapitalizationType);
UIKeyboardAppearance RCTUIKeyboardAppearanceFromKeyboardAppearance(
facebook::react::KeyboardAppearance keyboardAppearance);
UITextSpellCheckingType RCTUITextSpellCheckingTypeFromOptionalBool(facebook::better::optional<bool> spellCheck);
UITextFieldViewMode RCTUITextFieldViewModeFromTextInputAccessoryVisibilityMode(
facebook::react::TextInputAccessoryVisibilityMode mode);
UIKeyboardType RCTUIKeyboardTypeFromKeyboardType(facebook::react::KeyboardType keyboardType);
UIReturnKeyType RCTUIReturnKeyTypeFromReturnKeyType(facebook::react::ReturnKeyType returnKeyType);
API_AVAILABLE(ios(10.0))
UITextContentType RCTUITextContentTypeFromString(std::string const &contentType);
API_AVAILABLE(ios(12.0))
UITextInputPasswordRules *RCTUITextInputPasswordRulesFromString(std::string const &passwordRules);
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,198 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTTextInputUtils.h"
#import <React/RCTConversions.h>
using namespace facebook::react;
static NSAttributedString *RCTSanitizeAttributedString(NSAttributedString *attributedString)
{
// Here we need to remove text attributes specific to particular kind of TextInput on iOS (e.g. limiting line number).
// TODO: Implement it properly.
return [[NSAttributedString alloc] initWithString:attributedString.string];
}
void RCTCopyBackedTextInput(
UIView<RCTBackedTextInputViewProtocol> *fromTextInput,
UIView<RCTBackedTextInputViewProtocol> *toTextInput)
{
toTextInput.attributedText = RCTSanitizeAttributedString(fromTextInput.attributedText);
toTextInput.placeholder = fromTextInput.placeholder;
toTextInput.placeholderColor = fromTextInput.placeholderColor;
toTextInput.textContainerInset = fromTextInput.textContainerInset;
toTextInput.inputAccessoryView = fromTextInput.inputAccessoryView;
toTextInput.textInputDelegate = fromTextInput.textInputDelegate;
toTextInput.placeholderColor = fromTextInput.placeholderColor;
toTextInput.defaultTextAttributes = fromTextInput.defaultTextAttributes;
toTextInput.autocapitalizationType = fromTextInput.autocapitalizationType;
toTextInput.autocorrectionType = fromTextInput.autocorrectionType;
toTextInput.contextMenuHidden = fromTextInput.contextMenuHidden;
toTextInput.editable = fromTextInput.editable;
toTextInput.enablesReturnKeyAutomatically = fromTextInput.enablesReturnKeyAutomatically;
toTextInput.keyboardAppearance = fromTextInput.keyboardAppearance;
toTextInput.spellCheckingType = fromTextInput.spellCheckingType;
toTextInput.caretHidden = fromTextInput.caretHidden;
toTextInput.clearButtonMode = fromTextInput.clearButtonMode;
toTextInput.scrollEnabled = fromTextInput.scrollEnabled;
toTextInput.secureTextEntry = fromTextInput.secureTextEntry;
toTextInput.keyboardType = fromTextInput.keyboardType;
if (@available(iOS 10.0, *)) {
toTextInput.textContentType = fromTextInput.textContentType;
}
if (@available(iOS 12.0, *)) {
toTextInput.passwordRules = fromTextInput.passwordRules;
}
[toTextInput setSelectedTextRange:fromTextInput.selectedTextRange notifyDelegate:NO];
}
UITextAutocorrectionType RCTUITextAutocorrectionTypeFromOptionalBool(facebook::better::optional<bool> autoCorrect)
{
return autoCorrect.has_value() ? (*autoCorrect ? UITextAutocorrectionTypeYes : UITextAutocorrectionTypeNo)
: UITextAutocorrectionTypeDefault;
}
UITextAutocapitalizationType RCTUITextAutocapitalizationTypeFromAutocapitalizationType(
AutocapitalizationType autocapitalizationType)
{
switch (autocapitalizationType) {
case AutocapitalizationType::None:
return UITextAutocapitalizationTypeNone;
case AutocapitalizationType::Words:
return UITextAutocapitalizationTypeWords;
case AutocapitalizationType::Sentences:
return UITextAutocapitalizationTypeSentences;
case AutocapitalizationType::Characters:
return UITextAutocapitalizationTypeAllCharacters;
}
}
UIKeyboardAppearance RCTUIKeyboardAppearanceFromKeyboardAppearance(KeyboardAppearance keyboardAppearance)
{
switch (keyboardAppearance) {
case KeyboardAppearance::Default:
return UIKeyboardAppearanceDefault;
case KeyboardAppearance::Light:
return UIKeyboardAppearanceLight;
case KeyboardAppearance::Dark:
return UIKeyboardAppearanceDark;
}
}
UITextSpellCheckingType RCTUITextSpellCheckingTypeFromOptionalBool(facebook::better::optional<bool> spellCheck)
{
return spellCheck.has_value() ? (*spellCheck ? UITextSpellCheckingTypeYes : UITextSpellCheckingTypeNo)
: UITextSpellCheckingTypeDefault;
}
UITextFieldViewMode RCTUITextFieldViewModeFromTextInputAccessoryVisibilityMode(
facebook::react::TextInputAccessoryVisibilityMode mode)
{
switch (mode) {
case TextInputAccessoryVisibilityMode::Never:
return UITextFieldViewModeNever;
case TextInputAccessoryVisibilityMode::WhileEditing:
return UITextFieldViewModeWhileEditing;
case TextInputAccessoryVisibilityMode::UnlessEditing:
return UITextFieldViewModeUnlessEditing;
case TextInputAccessoryVisibilityMode::Always:
return UITextFieldViewModeAlways;
}
}
UIKeyboardType RCTUIKeyboardTypeFromKeyboardType(KeyboardType keyboardType)
{
switch (keyboardType) {
// Universal
case KeyboardType::Default:
return UIKeyboardTypeDefault;
case KeyboardType::EmailAddress:
return UIKeyboardTypeEmailAddress;
case KeyboardType::Numeric:
return UIKeyboardTypeDecimalPad;
case KeyboardType::PhonePad:
return UIKeyboardTypePhonePad;
case KeyboardType::NumberPad:
return UIKeyboardTypeNumberPad;
case KeyboardType::DecimalPad:
return UIKeyboardTypeDecimalPad;
// iOS-only
case KeyboardType::ASCIICapable:
return UIKeyboardTypeASCIICapable;
case KeyboardType::NumbersAndPunctuation:
return UIKeyboardTypeNumbersAndPunctuation;
case KeyboardType::URL:
return UIKeyboardTypeURL;
case KeyboardType::NamePhonePad:
return UIKeyboardTypeNamePhonePad;
case KeyboardType::Twitter:
return UIKeyboardTypeTwitter;
case KeyboardType::WebSearch:
return UIKeyboardTypeWebSearch;
case KeyboardType::ASCIICapableNumberPad:
if (@available(iOS 10.0, *)) {
return UIKeyboardTypeASCIICapableNumberPad;
} else {
return UIKeyboardTypeNumberPad;
}
// Android-only
case KeyboardType::VisiblePassword:
return UIKeyboardTypeDefault;
}
}
UIReturnKeyType RCTUIReturnKeyTypeFromReturnKeyType(ReturnKeyType returnKeyType)
{
switch (returnKeyType) {
case ReturnKeyType::Default:
return UIReturnKeyDefault;
case ReturnKeyType::Done:
return UIReturnKeyDone;
case ReturnKeyType::Go:
return UIReturnKeyGo;
case ReturnKeyType::Next:
return UIReturnKeyNext;
case ReturnKeyType::Search:
return UIReturnKeySearch;
case ReturnKeyType::Send:
return UIReturnKeySend;
// iOS-only
case ReturnKeyType::EmergencyCall:
return UIReturnKeyEmergencyCall;
case ReturnKeyType::Google:
return UIReturnKeyGoogle;
case ReturnKeyType::Join:
return UIReturnKeyJoin;
case ReturnKeyType::Route:
return UIReturnKeyRoute;
case ReturnKeyType::Yahoo:
return UIReturnKeyYahoo;
case ReturnKeyType::Continue:
return UIReturnKeyContinue;
// Android-only
case ReturnKeyType::None:
case ReturnKeyType::Previous:
return UIReturnKeyDefault;
}
}
API_AVAILABLE(ios(10.0))
UITextContentType RCTUITextContentTypeFromString(std::string const &contentType)
{
// TODO: Implement properly (T26519801).
return RCTNSStringFromStringNilIfEmpty(contentType);
}
API_AVAILABLE(ios(12.0))
UITextInputPasswordRules *RCTUITextInputPasswordRulesFromString(std::string const &passwordRules)
{
return [UITextInputPasswordRules passwordRulesWithDescriptor:RCTNSStringFromStringNilIfEmpty(passwordRules)];
}