Skip to content

Commit 933d19d

Browse files
Saadnajmiclaude
andauthored
chore(0.81): backport fixes (#2878, #2879, #2880) (#2884)
## Summary Backport of 3 fixes from `main` to `0.81-stable`: - **fix(fabric):** Switch default Text color to `labelColor` (#2878) - **fix(fabric):** fix Text overflow in ScrollView on first render (#2880) - **fix(fabric):** Add back compat layer for `validKeysDown` and `validKeysUp` (#2879) Each fix is a separate commit for easy rebasing when upstream PRs are updated. ### Conflict resolutions - **PR #2878:** 0.81-stable uses `RCTUIColor` (renamed from `RCTPlatformColor` on main). Resolved by keeping `RCTUIColor` while applying the `blackColor` → `labelColor` change. - **PRs #2880 and #2879** cherry-picked cleanly. #2879 (open PR) was squash-cherry-picked into a single commit. ## Test plan - [ ] Verify default text color respects dark/light mode - [ ] Verify Text in ScrollView renders correctly on first load - [ ] Verify legacy `validKeysDown`/`validKeysUp` props still work in Fabric 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e67245e commit 933d19d

16 files changed

Lines changed: 392 additions & 26 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
__default__: patch
3+
---
4+
5+
Backport fixes: default Text color to labelColor, Text overflow in ScrollView, validKeys compat layer

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@react-native-macos/monorepo",
3-
"version": "0.81.4",
3+
"version": "0.81.5",
44
"license": "MIT",
55
"packageManager": "yarn@4.13.0",
66
"scripts": {

packages/react-native/Libraries/Components/Pressable/Pressable.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,14 @@ function Pressable({
381381
// [macOS
382382
acceptsFirstMouse: acceptsFirstMouse !== false && !disabled,
383383
enableFocusRing: enableFocusRing !== false && !disabled,
384-
keyDownEvents: keyDownEvents ?? [{key: ' '}, {key: 'Enter'}],
384+
keyDownEvents:
385+
keyDownEvents ??
386+
// $FlowFixMe[unclear-type] Legacy props not in type definitions
387+
(((props: any).validKeysDown: mixed) == null &&
388+
// $FlowFixMe[unclear-type]
389+
((props: any).passthroughAllKeyEvents: mixed) !== true
390+
? [{key: ' '}, {key: 'Enter'}]
391+
: undefined),
385392
mouseDownCanMoveWindow: false,
386393
// macOS]
387394
};

packages/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ const RCTTextInputViewConfig: PartialViewConfigWithoutName = {
5252
captured: 'onSubmitEditingCapture',
5353
},
5454
},
55+
topKeyDown: {
56+
phasedRegistrationNames: {
57+
bubbled: 'onKeyDown',
58+
captured: 'onKeyDownCapture',
59+
},
60+
},
61+
topKeyUp: {
62+
phasedRegistrationNames: {
63+
bubbled: 'onKeyUp',
64+
captured: 'onKeyUpCapture',
65+
},
66+
},
5567
topTouchCancel: {
5668
phasedRegistrationNames: {
5769
bubbled: 'onTouchCancel',
@@ -173,6 +185,8 @@ const RCTTextInputViewConfig: PartialViewConfigWithoutName = {
173185
clearTextOnSubmit: true,
174186
grammarCheck: true,
175187
hideVerticalScrollIndicator: true,
188+
keyDownEvents: true,
189+
keyUpEvents: true,
176190
pastedTypes: true,
177191
submitKeyEvents: true,
178192
tooltip: true,
@@ -191,6 +205,8 @@ const RCTTextInputViewConfig: PartialViewConfigWithoutName = {
191205
onAutoCorrectChange: true,
192206
onSpellCheckChange: true,
193207
onGrammarCheckChange: true,
208+
onKeyDown: true,
209+
onKeyUp: true,
194210
// macOS]
195211
}),
196212
disableKeyboardShortcuts: true,

packages/react-native/Libraries/Components/TextInput/TextInput.js

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,13 @@ import flattenStyle from '../../StyleSheet/flattenStyle';
6060
import StyleSheet, {type TextStyleProp} from '../../StyleSheet/StyleSheet';
6161
import Text from '../../Text/Text';
6262
import TextAncestorContext from '../../Text/TextAncestorContext';
63+
// [macOS
64+
import processLegacyKeyProps, {
65+
hasLegacyKeyProps,
66+
stripLegacyKeyProps,
67+
} from '../../Utilities/normalizeLegacyHandledKeyEvents';
6368
import Platform from '../../Utilities/Platform';
69+
// macOS]
6470
import useMergeRefs from '../../Utilities/useMergeRefs';
6571
import TextInputState from './TextInputState';
6672
import invariant from 'invariant';
@@ -386,6 +392,11 @@ function useTextInputStateSynchronization({
386392
*
387393
*/
388394
function InternalTextInput(props: TextInputProps): React.Node {
395+
// [macOS
396+
const legacyKeyOverrides = hasLegacyKeyProps(props)
397+
? processLegacyKeyProps(props)
398+
: null;
399+
// macOS]
389400
const {
390401
'aria-busy': ariaBusy,
391402
'aria-checked': ariaChecked,
@@ -400,7 +411,9 @@ function InternalTextInput(props: TextInputProps): React.Node {
400411
selectionHandleColor,
401412
cursorColor,
402413
...otherProps
403-
} = props;
414+
// $FlowFixMe[unclear-type]
415+
} = ({...props, ...legacyKeyOverrides}: any); // [macOS]
416+
stripLegacyKeyProps(otherProps); // [macOS]
404417

405418
const inputRef = useRef<null | TextInputInstance>(null);
406419

@@ -581,10 +594,15 @@ function InternalTextInput(props: TextInputProps): React.Node {
581594
};
582595

583596
// [macOS
597+
const _keyDownEvents =
598+
legacyKeyOverrides?.keyDownEvents ?? props.keyDownEvents;
599+
const _keyUpEvents = legacyKeyOverrides?.keyUpEvents ?? props.keyUpEvents;
600+
const _origOnKeyDown = legacyKeyOverrides?.onKeyDown ?? props.onKeyDown;
601+
const _origOnKeyUp = legacyKeyOverrides?.onKeyUp ?? props.onKeyUp;
602+
584603
const _onKeyDown = (event: KeyEvent) => {
585-
const keyDownEvents = props.keyDownEvents;
586-
if (keyDownEvents != null && !event.isPropagationStopped()) {
587-
const isHandled = keyDownEvents.some(
604+
if (_keyDownEvents != null && !event.isPropagationStopped()) {
605+
const isHandled = _keyDownEvents.some(
588606
({key, metaKey, ctrlKey, altKey, shiftKey}: HandledKeyEvent) => {
589607
return (
590608
event.nativeEvent.key === key &&
@@ -599,13 +617,12 @@ function InternalTextInput(props: TextInputProps): React.Node {
599617
event.stopPropagation();
600618
}
601619
}
602-
props.onKeyDown?.(event);
620+
_origOnKeyDown?.(event);
603621
};
604622

605623
const _onKeyUp = (event: KeyEvent) => {
606-
const keyUpEvents = props.keyUpEvents;
607-
if (keyUpEvents != null && !event.isPropagationStopped()) {
608-
const isHandled = keyUpEvents.some(
624+
if (_keyUpEvents != null && !event.isPropagationStopped()) {
625+
const isHandled = _keyUpEvents.some(
609626
({key, metaKey, ctrlKey, altKey, shiftKey}: HandledKeyEvent) => {
610627
return (
611628
event.nativeEvent.key === key &&
@@ -620,7 +637,7 @@ function InternalTextInput(props: TextInputProps): React.Node {
620637
event.stopPropagation();
621638
}
622639
}
623-
props.onKeyUp?.(event);
640+
_origOnKeyUp?.(event);
624641
};
625642
// macOS]
626643

packages/react-native/Libraries/Components/View/View.js

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ import type {ViewProps} from './ViewPropTypes';
1313

1414
import * as ReactNativeFeatureFlags from '../../../src/private/featureflags/ReactNativeFeatureFlags';
1515
import TextAncestorContext from '../../Text/TextAncestorContext';
16+
// [macOS
17+
import processLegacyKeyProps, {
18+
hasLegacyKeyProps,
19+
stripLegacyKeyProps,
20+
} from '../../Utilities/normalizeLegacyHandledKeyEvents';
21+
// macOS]
1622
import ViewNativeComponent from './ViewNativeComponent';
1723
import * as React from 'react';
1824
import {use} from 'react';
@@ -30,13 +36,24 @@ component View(
3036
) {
3137
const hasTextAncestor = use(TextAncestorContext);
3238

39+
// [macOS
40+
const legacyKeyOverrides = hasLegacyKeyProps(props)
41+
? processLegacyKeyProps(props)
42+
: null;
43+
// macOS]
44+
3345
let actualView;
3446

3547
// [macOS
48+
const _keyDownEvents =
49+
legacyKeyOverrides?.keyDownEvents ?? props.keyDownEvents;
50+
const _keyUpEvents = legacyKeyOverrides?.keyUpEvents ?? props.keyUpEvents;
51+
const _origOnKeyDown = legacyKeyOverrides?.onKeyDown ?? props.onKeyDown;
52+
const _origOnKeyUp = legacyKeyOverrides?.onKeyUp ?? props.onKeyUp;
53+
3654
const _onKeyDown = (event: KeyEvent) => {
37-
const keyDownEvents = props.keyDownEvents;
38-
if (keyDownEvents != null && !event.isPropagationStopped()) {
39-
const isHandled = keyDownEvents.some(
55+
if (_keyDownEvents != null && !event.isPropagationStopped()) {
56+
const isHandled = _keyDownEvents.some(
4057
({key, metaKey, ctrlKey, altKey, shiftKey}: HandledKeyEvent) => {
4158
return (
4259
event.nativeEvent.key === key &&
@@ -51,13 +68,12 @@ component View(
5168
event.stopPropagation();
5269
}
5370
}
54-
props.onKeyDown?.(event);
71+
_origOnKeyDown?.(event);
5572
};
5673

5774
const _onKeyUp = (event: KeyEvent) => {
58-
const keyUpEvents = props.keyUpEvents;
59-
if (keyUpEvents != null && !event.isPropagationStopped()) {
60-
const isHandled = keyUpEvents.some(
75+
if (_keyUpEvents != null && !event.isPropagationStopped()) {
76+
const isHandled = _keyUpEvents.some(
6177
({key, metaKey, ctrlKey, altKey, shiftKey}: HandledKeyEvent) => {
6278
return (
6379
event.nativeEvent.key === key &&
@@ -72,7 +88,7 @@ component View(
7288
event.stopPropagation();
7389
}
7490
}
75-
props.onKeyUp?.(event);
91+
_origOnKeyUp?.(event);
7692
};
7793
// macOS]
7894

@@ -96,10 +112,12 @@ component View(
96112
id,
97113
tabIndex,
98114
...otherProps
99-
} = props;
115+
// $FlowFixMe[unclear-type]
116+
} = ({...props, ...legacyKeyOverrides}: any); // [macOS]
100117

101118
// Since we destructured props, we can now treat it as mutable
102119
const processedProps = otherProps as {...ViewProps};
120+
stripLegacyKeyProps(processedProps); // [macOS]
103121

104122
const parsedAriaLabelledBy = ariaLabelledBy?.split(/\s*,\s*/g);
105123
if (parsedAriaLabelledBy !== undefined) {
@@ -195,7 +213,9 @@ component View(
195213
nativeID,
196214
tabIndex,
197215
...otherProps
198-
} = props;
216+
// $FlowFixMe[unclear-type]
217+
} = ({...props, ...legacyKeyOverrides}: any); // [macOS]
218+
stripLegacyKeyProps(otherProps); // [macOS]
199219
const _accessibilityLabelledBy =
200220
ariaLabelledBy?.split(/\s*,\s*/g) ?? accessibilityLabelledBy;
201221

packages/react-native/Libraries/Text/RCTTextAttributes.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ - (CGFloat)effectiveFontSizeMultiplier
277277

278278
- (RCTUIColor *)effectiveForegroundColor // [macOS]
279279
{
280-
RCTUIColor *effectiveForegroundColor = _foregroundColor ?: [RCTUIColor blackColor]; // [macOS]
280+
RCTUIColor *effectiveForegroundColor = _foregroundColor ?: [RCTTextAttributes defaultForegroundColor]; // [macOS]
281281

282282
if (!isnan(_opacity)) {
283283
effectiveForegroundColor =

packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ - (instancetype)initWithFrame:(CGRect)frame
6969
_textInputDelegateAdapter = [[RCTBackedTextViewDelegateAdapter alloc] initWithTextView:self];
7070

7171
self.backgroundColor = [RCTUIColor clearColor]; // [macOS]
72-
self.textColor = [RCTUIColor blackColor]; // [macOS]
72+
self.textColor = [RCTUIColor labelColor]; // [macOS]
7373
// This line actually removes 5pt (default value) left and right padding in UITextView.
7474
#if !TARGET_OS_OSX // [macOS]
7575
self.textContainer.lineFragmentPadding = 0;

packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ - (void)enforceTextAttributesIfNeeded
127127

128128
NSDictionary<NSAttributedStringKey, id> *textAttributes = [[_textAttributes effectiveTextAttributes] mutableCopy];
129129
if ([textAttributes valueForKey:NSForegroundColorAttributeName] == nil) {
130-
[textAttributes setValue:[RCTUIColor blackColor] forKey:NSForegroundColorAttributeName]; // [macOS]
130+
[textAttributes setValue:[RCTUIColor labelColor] forKey:NSForegroundColorAttributeName]; // [macOS]
131131
}
132132

133133
backedTextInputView.defaultTextAttributes = textAttributes;

0 commit comments

Comments
 (0)