Skip to content

Commit

Permalink
[0.74-stable] Make TextInput events more reliable (#2159 + #2160) (#2168
Browse files Browse the repository at this point in the history
)

* Deduplicate `textInputDid(Begin|End)Editing` calls for multiline `<TextInput>` elements (#2159)

* Add _isCurrentlyEditing to RCTBaseTextInputView

* Move _isCurrentlyEditing check earlier in textInputDidBeginEditing

* Adjust comment

* nit: remove extra newline

* Limit changes to macOS

---------

Co-authored-by: Adam Gleitman <adgleitm@microsoft.com>

* Prevent spurious onBlur/onEndEditing events in `<TextInput>` elements with placeholder text (#2160)

* Add _isUpdatingPlaceholderText to prevent spurious "did end editing" notifications

* Organize macOS tags and ifdef blocks

---------

Co-authored-by: Adam Gleitman <adgleitm@microsoft.com>

---------

Co-authored-by: Adam Gleitman <adgleitm@microsoft.com>
  • Loading branch information
amgleitman and Adam Gleitman committed Aug 19, 2024
1 parent d10e281 commit 2cc0a2e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ @implementation RCTBaseTextInputView {
BOOL _hasInputAccessoryView;
// [macOS] remove explicit _predictedText ivar declaration
BOOL _didMoveToWindow;
#if TARGET_OS_OSX // [macOS avoids duplicating effects of textInputDid(Begin|End)Editing calls
BOOL _isCurrentlyEditing;
#endif // macOS]
}

#if !TARGET_OS_OSX // [macOS]
Expand Down Expand Up @@ -71,6 +74,9 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
if (self = [super initWithEventDispatcher:bridge.eventDispatcher]) { // [macOS]
_bridge = bridge;
_eventDispatcher = bridge.eventDispatcher;
#if TARGET_OS_OSX // [macOS
_isCurrentlyEditing = NO;
#endif // macOS]
}

return self;
Expand Down Expand Up @@ -446,6 +452,13 @@ - (BOOL)textInputShouldBeginEditing

- (void)textInputDidBeginEditing
{
#if TARGET_OS_OSX // [macOS consolidate duplicate callbacks
if (_isCurrentlyEditing) {
return;
}
_isCurrentlyEditing = YES;
#endif // macOS]

if (_clearTextOnFocus) {
self.backedTextInputView.attributedText = [NSAttributedString new];
}
Expand Down Expand Up @@ -474,6 +487,13 @@ - (BOOL)textInputShouldEndEditing

- (void)textInputDidEndEditing
{
#if TARGET_OS_OSX // [macOS consolidate duplicate callbacks
if (!_isCurrentlyEditing) {
return;
}
_isCurrentlyEditing = NO;
#endif // macOS]

self.ghostText = nil; // [macOS]

[_eventDispatcher sendTextEventWithType:RCTTextEventTypeEnd
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ @implementation RCTUITextField {
#endif
RCTBackedTextFieldDelegateAdapter *_textInputDelegateAdapter;
NSDictionary<NSAttributedStringKey, id> *_defaultTextAttributes;
#if TARGET_OS_OSX // [macOS
BOOL _isUpdatingPlaceholderText;
#endif // macOS]
}

#if TARGET_OS_OSX // [macOS
Expand All @@ -116,6 +119,9 @@ - (instancetype)initWithFrame:(CGRect)frame

_textInputDelegateAdapter = [[RCTBackedTextFieldDelegateAdapter alloc] initWithTextField:self];
_scrollEnabled = YES;
#if TARGET_OS_OSX // [macOS
_isUpdatingPlaceholderText = NO;
#endif // macOS]
}

return self;
Expand Down Expand Up @@ -361,8 +367,11 @@ - (void)_updatePlaceholder
self.attributedPlaceholder = [[NSAttributedString alloc] initWithString:self.placeholder ?: @""
attributes:[self _placeholderTextAttributes]];
#else // [macOS
// Set _isUpdatingPlaceholderText to manually suppress RCTUITextFieldDelegate's textFieldEndEditing
_isUpdatingPlaceholderText = YES;
self.placeholderAttributedString = [[NSAttributedString alloc] initWithString:self.placeholder ?: @""
attributes:[self _placeholderTextAttributes]];
_isUpdatingPlaceholderText = NO;
#endif // macOS]
}

Expand Down Expand Up @@ -485,10 +494,17 @@ - (void)textDidChange:(NSNotification *)notification
[delegate textFieldDidChange:self];
}
}

- (void)textDidEndEditing:(NSNotification *)notification
{
[super textDidEndEditing:notification];
[super textDidEndEditing:notification];

// On macOS, setting placeholderAttributedString causes AppKit to call textDidEndEditing.
// We don't want this to propagate or else we get unexpected onBlur/onEndEditing events.
if (_isUpdatingPlaceholderText) {
return;
}

id<RCTUITextFieldDelegate> delegate = self.delegate;
if ([delegate respondsToSelector:@selector(textFieldEndEditing:)]) {
[delegate textFieldEndEditing:self];
Expand Down

0 comments on commit 2cc0a2e

Please sign in to comment.