From 44f84ec865e6fdbe69813b32aa0357e1ee1e5e66 Mon Sep 17 00:00:00 2001 From: Bron Davies Date: Fri, 23 Oct 2026 08:46:14 -0600 Subject: [PATCH] fix(macos): stop a secure TextInput throwing as it takes focus Since RCTUISecureTextField became an RCTUITextField subclass with an NSSecureTextFieldCell (#2895), AppKit refuses it as the secure field editor's delegate: -[NSSecureTextView setDelegate:] throws "NSSecureTextFieldCell is not secure because the secure field editor's delegate must be an NSSecureTextField!" when the field becomes first responder. It now answers isKindOfClass: for NSSecureTextField. NSSecureTextView then also sends it -_shouldShowIndicators while drawing, which NSSecureTextField answers from a flag that is off by default, so it answers NO. --- .../Singleline/macOS/RCTUISecureTextField.mm | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/react-native/Libraries/Text/TextInput/Singleline/macOS/RCTUISecureTextField.mm b/packages/react-native/Libraries/Text/TextInput/Singleline/macOS/RCTUISecureTextField.mm index c5aeaf80ac62..d1bbb29cb8a0 100644 --- a/packages/react-native/Libraries/Text/TextInput/Singleline/macOS/RCTUISecureTextField.mm +++ b/packages/react-native/Libraries/Text/TextInput/Singleline/macOS/RCTUISecureTextField.mm @@ -85,6 +85,24 @@ + (Class)cellClass return RCTUISecureTextFieldCell.class; } +// AppKit's secure field editor (NSSecureTextView) requires its delegate to be an NSSecureTextField, +// and throws as the field takes focus when it is not ("NSSecureTextFieldCell is not secure because +// the secure field editor's delegate must be an NSSecureTextField!"). This class subclasses +// RCTUITextField to share its behaviour, but its cell is an NSSecureTextFieldCell, which masks the +// text and turns on secure keyboard input, so it answers as an NSSecureTextField. +- (BOOL)isKindOfClass:(Class)aClass +{ + return aClass == [NSSecureTextField class] || [super isKindOfClass:aClass]; +} + +// Taken for an NSSecureTextField, the field is also asked this by NSSecureTextView as it draws, and +// an unanswered message throws there. NSSecureTextField answers from a flag that is off unless its +// private setter turns it on, so this answers NO, as an NSSecureTextField does by default. +- (BOOL)_shouldShowIndicators +{ + return NO; +} + @end #endif // TARGET_OS_OSX