Skip to content

Commit 764c692

Browse files
Saadnajmiclaude
andauthored
fix(0.81, fabric): textInput text color not adapting to appearance changes (#2914)
## Summary Backport of the changes from branch `fix-textinput-dark-mode-new-arch` to `0.81-stable`. See #2913 for full details. ## Test Plan Same as the original PR. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8acac29 commit 764c692

File tree

2 files changed

+48
-1
lines changed

2 files changed

+48
-1
lines changed

packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,30 @@ - (void)didMoveToWindow
170170
[self _restoreTextSelection];
171171
}
172172

173+
// [macOS
174+
- (void)_updateDefaultTextAttributes
175+
{
176+
const auto &props = static_cast<const TextInputProps &>(*_props);
177+
NSMutableDictionary<NSAttributedStringKey, id> *attrs =
178+
RCTNSTextAttributesFromTextAttributes(props.getEffectiveTextAttributes(RCTFontSizeMultiplier()));
179+
180+
_backedTextInputView.defaultTextAttributes = attrs;
181+
182+
// Also update the existing attributed text so the visible text re-renders
183+
// with the new color (defaultTextAttributes only affects newly typed text).
184+
// Wrap in _comingFromJS to prevent textInputDidChange from pushing a state
185+
// update back to the shadow tree, which would overwrite our fresh colors
186+
// with the stale cached attributed string.
187+
NSString *currentText = _backedTextInputView.attributedText.string;
188+
if (currentText.length > 0) {
189+
NSAttributedString *updated = [[NSAttributedString alloc] initWithString:currentText attributes:attrs];
190+
_comingFromJS = YES;
191+
_backedTextInputView.attributedText = updated;
192+
_comingFromJS = NO;
193+
}
194+
}
195+
// macOS]
196+
173197
#if !TARGET_OS_OSX // [macOS]
174198
// TODO: replace with registerForTraitChanges once iOS 17.0 is the lowest supported version
175199
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
@@ -183,8 +207,20 @@ - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
183207
_backedTextInputView.defaultTextAttributes =
184208
RCTNSTextAttributesFromTextAttributes(newTextInputProps.getEffectiveTextAttributes(RCTFontSizeMultiplier()));
185209
}
210+
211+
// [macOS
212+
if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) {
213+
[self _updateDefaultTextAttributes];
214+
}
215+
// macOS]
216+
}
217+
#else // [macOS
218+
- (void)viewDidChangeEffectiveAppearance
219+
{
220+
[super viewDidChangeEffectiveAppearance];
221+
[self _updateDefaultTextAttributes];
186222
}
187-
#endif // [macOS]
223+
#endif // macOS]
188224

189225
- (void)reactUpdateResponderOffsetForScrollView:(RCTScrollViewComponentView *)scrollView
190226
{

packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,14 @@ inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const Tex
146146
{
147147
RCTUIColor *effectiveForegroundColor = RCTUIColorFromSharedColor(textAttributes.foregroundColor) ?: [RCTUIColor labelColor]; // [macOS]
148148

149+
#if TARGET_OS_OSX // [macOS
150+
// On macOS, colorWithAlphaComponent: converts dynamic system colors (like
151+
// NSColor.labelColor) to static resolved colors, preventing them from
152+
// adapting to appearance changes. Skip when opacity is 1.0 (a no-op).
153+
if (!isnan(textAttributes.opacity) && textAttributes.opacity != 1.0f) {
154+
#else // macOS]
149155
if (!isnan(textAttributes.opacity)) {
156+
#endif
150157
effectiveForegroundColor = [effectiveForegroundColor
151158
colorWithAlphaComponent:CGColorGetAlpha(effectiveForegroundColor.CGColor) * textAttributes.opacity];
152159
}
@@ -158,7 +165,11 @@ inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const Tex
158165
{
159166
RCTUIColor *effectiveBackgroundColor = RCTUIColorFromSharedColor(textAttributes.backgroundColor); // [macOS]
160167

168+
#if TARGET_OS_OSX // [macOS
169+
if (effectiveBackgroundColor && !isnan(textAttributes.opacity) && textAttributes.opacity != 1.0f) {
170+
#else // macOS]
161171
if (effectiveBackgroundColor && !isnan(textAttributes.opacity)) {
172+
#endif
162173
effectiveBackgroundColor = [effectiveBackgroundColor
163174
colorWithAlphaComponent:CGColorGetAlpha(effectiveBackgroundColor.CGColor) * textAttributes.opacity];
164175
}

0 commit comments

Comments
 (0)