react-native/Libraries/Text/RCTTextFieldManager.m

128 lines
4.8 KiB
Mathematica
Raw Normal View History

/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "RCTTextFieldManager.h"
#import "RCTBridge.h"
#import "RCTShadowView.h"
#import "RCTTextField.h"
#import "RCTFont.h"
@interface RCTTextFieldManager() <UITextFieldDelegate>
@end
@implementation RCTTextFieldManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
RCTTextField *textField = [[RCTTextField alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
textField.delegate = self;
return textField;
}
- (BOOL)textField:(RCTTextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// Only allow single keypresses for onKeyPress, pasted text will not be sent.
if (textField.textWasPasted) {
textField.textWasPasted = NO;
} else {
[textField sendKeyValueForString:string];
}
if (textField.maxLength == nil || [string isEqualToString:@"\n"]) { // Make sure forms can be submitted via return
return YES;
}
NSUInteger allowedLength = textField.maxLength.integerValue - MIN(textField.maxLength.integerValue, textField.text.length) + range.length;
if (string.length > allowedLength) {
if (string.length > 1) {
// Truncate the input string so the result is exactly maxLength
NSString *limitedString = [string substringToIndex:allowedLength];
NSMutableString *newString = textField.text.mutableCopy;
[newString replaceCharactersInRange:range withString:limitedString];
textField.text = newString;
// Collapse selection at end of insert to match normal paste behavior
UITextPosition *insertEnd = [textField positionFromPosition:textField.beginningOfDocument
offset:(range.location + allowedLength)];
textField.selectedTextRange = [textField textRangeFromPosition:insertEnd toPosition:insertEnd];
[textField textFieldDidChange];
}
return NO;
} else {
return YES;
}
}
// This method allows us to detect a `Backspace` keyPress
// even when there is no more text in the TextField
- (BOOL)keyboardInputShouldDelete:(RCTTextField *)textField
{
[self textField:textField shouldChangeCharactersInRange:NSMakeRange(0, 0) replacementString:@""];
return YES;
}
- (BOOL)textFieldShouldEndEditing:(RCTTextField *)textField
{
return [textField textFieldShouldEndEditing:textField];
}
RCT_EXPORT_VIEW_PROPERTY(caretHidden, BOOL)
RCT_EXPORT_VIEW_PROPERTY(autoCorrect, BOOL)
RCT_REMAP_VIEW_PROPERTY(editable, enabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(placeholder, NSString)
RCT_EXPORT_VIEW_PROPERTY(placeholderTextColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(selection, RCTTextSelection)
RCT_EXPORT_VIEW_PROPERTY(text, NSString)
[ReactNative] TextInput bug fixes and features Summary: This introduces event counts to make sure JS doesn't set out of date values on native text inputs, which can cause dropped characters and can mess with autocomplete, and obviates the need for the input buffering which added lag and complexity to the component. Made sure to test simulated super-slow JS text event processing to make sure characters aren't dropped, as well as typing obviously correctable words and making sure autocomplete works as expected. TextInput is now a controlled input by default without causing any issues for most cases, so I removed the `controlled` prop. Fixes selection state jumping by restoring it after setting new text values, so highlighting the middle of some text in the new ReWrite example and hitting space will replace that selection with an underscore and keep the cursor at a sensible position as expected, instead of jumping to the end. Ads `maxLength` prop to support the most commonly needed syncronous behavior: preventing the user from typing too many characters. It can also be used to prevent users from continuing to type after entering special characters by changing it to the current length after a regex match. Made sure to verify it works well with pasted input (including in the middle of existing text), truncating it and collapsing the selection the same way it does on the web. Fixes bug in TextEventsExample where it wouldn't show the submit and end events, even though there were firing correctly.
2015-07-21 19:37:24 +00:00
RCT_EXPORT_VIEW_PROPERTY(maxLength, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(clearButtonMode, UITextFieldViewMode)
RCT_REMAP_VIEW_PROPERTY(clearTextOnFocus, clearsOnBeginEditing, BOOL)
RCT_EXPORT_VIEW_PROPERTY(selectTextOnFocus, BOOL)
RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL)
RCT_EXPORT_VIEW_PROPERTY(keyboardType, UIKeyboardType)
RCT_EXPORT_VIEW_PROPERTY(keyboardAppearance, UIKeyboardAppearance)
RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(returnKeyType, UIReturnKeyType)
RCT_EXPORT_VIEW_PROPERTY(enablesReturnKeyAutomatically, BOOL)
RCT_EXPORT_VIEW_PROPERTY(secureTextEntry, BOOL)
RCT_REMAP_VIEW_PROPERTY(password, secureTextEntry, BOOL) // backwards compatibility
RCT_REMAP_VIEW_PROPERTY(color, textColor, UIColor)
RCT_REMAP_VIEW_PROPERTY(autoCapitalize, autocapitalizationType, UITextAutocapitalizationType)
RCT_REMAP_VIEW_PROPERTY(textAlign, textAlignment, NSTextAlignment)
RCT_REMAP_VIEW_PROPERTY(selectionColor, tintColor, UIColor)
RCT_CUSTOM_VIEW_PROPERTY(fontSize, NSNumber, RCTTextField)
{
view.font = [RCTFont updateFont:view.font withSize:json ?: @(defaultView.font.pointSize)];
}
RCT_CUSTOM_VIEW_PROPERTY(fontWeight, NSString, __unused RCTTextField)
{
view.font = [RCTFont updateFont:view.font withWeight:json]; // defaults to normal
}
RCT_CUSTOM_VIEW_PROPERTY(fontStyle, NSString, __unused RCTTextField)
{
view.font = [RCTFont updateFont:view.font withStyle:json]; // defaults to normal
}
RCT_CUSTOM_VIEW_PROPERTY(fontFamily, NSString, RCTTextField)
{
view.font = [RCTFont updateFont:view.font withFamily:json ?: defaultView.font.familyName];
}
[ReactNative] TextInput bug fixes and features Summary: This introduces event counts to make sure JS doesn't set out of date values on native text inputs, which can cause dropped characters and can mess with autocomplete, and obviates the need for the input buffering which added lag and complexity to the component. Made sure to test simulated super-slow JS text event processing to make sure characters aren't dropped, as well as typing obviously correctable words and making sure autocomplete works as expected. TextInput is now a controlled input by default without causing any issues for most cases, so I removed the `controlled` prop. Fixes selection state jumping by restoring it after setting new text values, so highlighting the middle of some text in the new ReWrite example and hitting space will replace that selection with an underscore and keep the cursor at a sensible position as expected, instead of jumping to the end. Ads `maxLength` prop to support the most commonly needed syncronous behavior: preventing the user from typing too many characters. It can also be used to prevent users from continuing to type after entering special characters by changing it to the current length after a regex match. Made sure to verify it works well with pasted input (including in the middle of existing text), truncating it and collapsing the selection the same way it does on the web. Fixes bug in TextEventsExample where it wouldn't show the submit and end events, even though there were firing correctly.
2015-07-21 19:37:24 +00:00
RCT_EXPORT_VIEW_PROPERTY(mostRecentEventCount, NSInteger)
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(RCTShadowView *)shadowView
{
NSNumber *reactTag = shadowView.reactTag;
UIEdgeInsets padding = shadowView.paddingAsInsets;
return ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTTextField *> *viewRegistry) {
viewRegistry[reactTag].contentInset = padding;
};
}
@end