diff --git a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm index d487cf251dfbf9..afccd690477ac0 100644 --- a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm +++ b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm @@ -93,6 +93,9 @@ @implementation RCTUITextField { #endif RCTBackedTextFieldDelegateAdapter *_textInputDelegateAdapter; NSDictionary *_defaultTextAttributes; +#if TARGET_OS_OSX // [macOS + BOOL _isUpdatingPlaceholderText; +#endif // macOS] } #if TARGET_OS_OSX // [macOS @@ -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; @@ -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] } @@ -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 delegate = self.delegate; if ([delegate respondsToSelector:@selector(textFieldEndEditing:)]) { [delegate textFieldEndEditing:self];