Skip to content

Commit

Permalink
Shim RCTTextInput (#1681)
Browse files Browse the repository at this point in the history
Co-authored-by: Shawn Dempsey <shawndempsey@fb.com>
  • Loading branch information
shwanton and Shawn Dempsey authored Jan 25, 2023
1 parent beefc1b commit 3467d0d
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ @interface RCTTextInputComponentView () <RCTBackedTextInputDelegate, RCTTextInpu

@implementation RCTTextInputComponentView {
TextInputShadowNode::ConcreteState::Shared _state;
RCTUIView<RCTBackedTextInputViewProtocol> *_backedTextInputView; // [macOS]
#if !TARGET_OS_OSX // [macOS]
RCTUIView<RCTBackedTextInputViewProtocol> *_backedTextInputView;
#else // [macOS
RCTUITextView<RCTBackedTextInputViewProtocol> *_backedTextInputView;
#endif // macOS]
NSUInteger _mostRecentEventCount;
NSAttributedString *_lastStringStateWasUpdatedWith;

Expand Down Expand Up @@ -67,7 +71,11 @@ - (instancetype)initWithFrame:(CGRect)frame
_props = defaultProps;
auto &props = *defaultProps;

#if !TARGET_OS_OSX // [macOS]
_backedTextInputView = props.traits.multiline ? [RCTUITextView new] : [RCTUITextField new];
#else // [macOS
_backedTextInputView = [RCTUITextView new];
#endif // macOS]
_backedTextInputView.textInputDelegate = self;
_ignoreNextTextInputCall = NO;
_comingFromJS = NO;
Expand Down Expand Up @@ -480,25 +488,23 @@ - (void)setTextAndSelection:(NSInteger)eventCount

- (void)setDefaultInputAccessoryView
{
#if !TARGET_OS_OSX // [macOS]
// InputAccessoryView component sets the inputAccessoryView when inputAccessoryViewID exists
if (_backedTextInputView.inputAccessoryViewID) {
if (_backedTextInputView.isFirstResponder) {
#if !TARGET_OS_OSX // [macOS]
[_backedTextInputView reloadInputViews];
#endif // [macOS]
}
return;
}

#if !TARGET_OS_OSX // [macOS]
UIKeyboardType keyboardType = _backedTextInputView.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) &&
_backedTextInputView.returnKeyType == UIReturnKeyDone;
(keyboardType == UIKeyboardTypeNumberPad || keyboardType == UIKeyboardTypePhonePad ||
keyboardType == UIKeyboardTypeDecimalPad || keyboardType == UIKeyboardTypeASCIICapableNumberPad) &&
_backedTextInputView.returnKeyType == UIReturnKeyDone;

if ((_backedTextInputView.inputAccessoryView != nil) == shouldHaveInputAccesoryView) {
return;
Expand All @@ -508,32 +514,30 @@ - (void)setDefaultInputAccessoryView
UIToolbar *toolbarView = [UIToolbar new];
[toolbarView sizeToFit];
UIBarButtonItem *flexibleSpace =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneButton =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:@selector(handleInputAccessoryDoneButton)];
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:@selector(handleInputAccessoryDoneButton)];
toolbarView.items = @[ flexibleSpace, doneButton ];
_backedTextInputView.inputAccessoryView = toolbarView;
} else {
_backedTextInputView.inputAccessoryView = nil;
}
#endif // [macOS]


if (_backedTextInputView.isFirstResponder) {
#if !TARGET_OS_OSX // [macOS]
[_backedTextInputView reloadInputViews];
#endif // [macOS]
}
#endif // [macOS]
}

- (void)handleInputAccessoryDoneButton
{
if ([self textInputShouldReturn]) {
#if !TARGET_OS_OSX // [macOS]
if ([self textInputShouldReturn]) {
[_backedTextInputView endEditing:YES];
#endif // [macOS]
}
#endif // [macOS]
}

#pragma mark - Other
Expand Down Expand Up @@ -635,7 +639,11 @@ - (void)_setAttributedString:(NSAttributedString *)attributedString
- (void)_setMultiline:(BOOL)multiline
{
[_backedTextInputView removeFromSuperview];
RCTUIView<RCTBackedTextInputViewProtocol> *backedTextInputView = multiline ? [RCTUITextView new] : [RCTUITextField new]; // [macOS]
#if !TARGET_OS_OSX // [macOS]
RCTUIView<RCTBackedTextInputViewProtocol> *backedTextInputView = multiline ? [RCTUITextView new] : [RCTUITextField new];
#else // [macOS
RCTUITextView<RCTBackedTextInputViewProtocol> *backedTextInputView = [RCTUITextView new];
#endif // macOS]
backedTextInputView.frame = _backedTextInputView.frame;
RCTCopyBackedTextInput(_backedTextInputView, backedTextInputView);
_backedTextInputView = backedTextInputView;
Expand Down Expand Up @@ -665,17 +673,19 @@ - (BOOL)_textOf:(NSAttributedString *)newText equals:(NSAttributedString *)oldTe
}];

BOOL shouldFallbackToBareTextComparison =
[_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] ||
#if !TARGET_OS_OSX // [macOS]
[_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] ||
_backedTextInputView.markedTextRange || _backedTextInputView.isSecureTextEntry || fontHasBeenUpdatedBySystem;
[_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"dictation"] ||
[_backedTextInputView.textInputMode.primaryLanguage isEqualToString:@"ko-KR"] ||
_backedTextInputView.markedTextRange ||
_backedTextInputView.isSecureTextEntry ||
#else // [macOS
// There are multiple Korean input sources (2-Set, 3-Set, etc). Check substring instead instead
[[[self.backedTextInputView inputContext] selectedKeyboardInputSource] containsString:@"com.apple.inputmethod.Korean"] ||
[self.backedTextInputView hasMarkedText] ||
[self.backedTextInputView isKindOfClass:[NSSecureTextField class]] ||
fontHasBeenUpdatedBySystem;
// There are multiple Korean input sources (2-Set, 3-Set, etc). Check substring instead instead
[[[_backedTextInputView inputContext] selectedKeyboardInputSource] containsString:@"com.apple.inputmethod.Korean"] ||
[_backedTextInputView hasMarkedText] ||
[_backedTextInputView isKindOfClass:[NSSecureTextField class]] ||
#endif // macOS]
fontHasBeenUpdatedBySystem;

if (shouldFallbackToBareTextComparison) {
return ([newText.string isEqualToString:oldText.string]);
} else {
Expand Down
21 changes: 14 additions & 7 deletions React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,28 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <optional>

#import <React/RCTUIKit.h> // [macOS]

#import <optional>
#import <React/RCTUITextField.h> // [macOS]
#import <React/RCTUITextView.h> // [macOS]

#import <React/RCTBackedTextInputViewProtocol.h>
#import <react/renderer/components/iostextinput/primitives.h>

NS_ASSUME_NONNULL_BEGIN

void RCTCopyBackedTextInput(
RCTUIView<RCTBackedTextInputViewProtocol> *fromTextInput, // [macOS]
RCTUIView<RCTBackedTextInputViewProtocol> *toTextInput); // [macOS]

#if !TARGET_OS_OSX // [macOS]
#if !TARGET_OS_OSX // [macOS]
RCTUIView<RCTBackedTextInputViewProtocol> *fromTextInput,
RCTUIView<RCTBackedTextInputViewProtocol> *toTextInput
#else // [macOS
RCTUITextView<RCTBackedTextInputViewProtocol> *fromTextInput,
RCTUITextView<RCTBackedTextInputViewProtocol> *toTextInput
#endif // macOS]
);

#if !TARGET_OS_OSX // [macOS]
UITextAutocorrectionType RCTUITextAutocorrectionTypeFromOptionalBool(std::optional<bool> autoCorrect);

UITextAutocapitalizationType RCTUITextAutocapitalizationTypeFromAutocapitalizationType(
Expand All @@ -41,6 +48,6 @@ UITextContentType RCTUITextContentTypeFromString(std::string const &contentType)

API_AVAILABLE(ios(12.0))
UITextInputPasswordRules *RCTUITextInputPasswordRulesFromString(std::string const &passwordRules);
#endif // [macOS]
#endif // [macOS]

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@
}

void RCTCopyBackedTextInput(
#if !TARGET_OS_OSX // [macOS]
RCTUIView<RCTBackedTextInputViewProtocol> *fromTextInput,
RCTUIView<RCTBackedTextInputViewProtocol> *toTextInput) // [macOS]
RCTUIView<RCTBackedTextInputViewProtocol> *toTextInput
#else // [macOS
RCTUITextView<RCTBackedTextInputViewProtocol> *fromTextInput,
RCTUITextView<RCTBackedTextInputViewProtocol> *toTextInput
#endif // macOS]
)
{
toTextInput.attributedText = RCTSanitizeAttributedString(fromTextInput.attributedText);
toTextInput.placeholder = fromTextInput.placeholder;
Expand Down

0 comments on commit 3467d0d

Please sign in to comment.