Skip to content

Commit aeae709

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Route selectable text through NativeSelectableText (facebook#55678)
Summary: Wire up the JS side to use the new SelectableTextViewManager native component. When enablePreparedTextLayout() is on, NativeSelectableText resolves to RCTSelectableText, routing selectable text through ReactTextView instead of PreparedLayoutTextView. When the flag is off, NativeSelectableText falls back to NativeText, so behavior is identical to before. Refactor NativePressableText and NativePressableVirtualText from arrow function component expressions to component declarations (PressableText and PressableVirtualText). PressableText now accepts a selectable prop to choose between NativeSelectableText and NativeText. Add a check(!isSelectable) guard in PreparedLayoutTextViewManager.setSelectable since selectable text now routes to SelectableTextViewManager instead. Changelog: [Internal] Reviewed By: javache Differential Revision: D93829401
1 parent 008616e commit aeae709

File tree

4 files changed

+55
-48
lines changed

4 files changed

+55
-48
lines changed

packages/react-native/Libraries/Text/Text.js

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,18 @@ import processColor from '../StyleSheet/processColor';
2222
import StyleSheet from '../StyleSheet/StyleSheet';
2323
import Platform from '../Utilities/Platform';
2424
import TextAncestorContext from './TextAncestorContext';
25-
import {NativeText, NativeVirtualText} from './TextNativeComponent';
25+
import {
26+
NativeSelectableText,
27+
NativeText,
28+
NativeVirtualText,
29+
} from './TextNativeComponent';
2630
import * as React from 'react';
2731
import {useContext, useMemo, useState} from 'react';
2832

2933
export type {TextProps} from './TextProps';
3034

3135
type TextForwardRef = React.ElementRef<
32-
typeof NativeText | typeof NativeVirtualText,
36+
typeof NativeText | typeof NativeVirtualText | typeof NativeSelectableText,
3337
>;
3438

3539
/**
@@ -269,7 +273,7 @@ const TextImpl: component(
269273
processedProps.children = children;
270274
if (isPressable) {
271275
return (
272-
<NativePressableVirtualText
276+
<PressableVirtualText
273277
ref={forwardedRef}
274278
textProps={processedProps}
275279
textPressabilityProps={textPressabilityProps ?? {}}
@@ -289,14 +293,20 @@ const TextImpl: component(
289293

290294
if (isPressable) {
291295
nativeText = (
292-
<NativePressableText
296+
<PressableText
293297
ref={forwardedRef}
298+
selectable={_selectable}
294299
textProps={processedProps}
295300
textPressabilityProps={textPressabilityProps ?? {}}
296301
/>
297302
);
298303
} else {
299-
nativeText = <NativeText {...processedProps} ref={forwardedRef} />;
304+
nativeText =
305+
_selectable === true ? (
306+
<NativeSelectableText {...processedProps} ref={forwardedRef} />
307+
) : (
308+
<NativeText {...processedProps} ref={forwardedRef} />
309+
);
300310
}
301311

302312
if (children == null) {
@@ -463,28 +473,17 @@ function useTextPressability({
463473
);
464474
}
465475

466-
type NativePressableTextProps = Readonly<{
467-
textProps: NativeTextProps,
468-
textPressabilityProps: TextPressabilityProps,
469-
}>;
470-
471476
/**
472477
* Wrap the NativeVirtualText component and initialize pressability.
473478
*
474479
* This logic is split out from the main Text component to enable the more
475480
* expensive pressability logic to be only initialized when needed.
476481
*/
477-
const NativePressableVirtualText: component(
478-
ref: React.RefSetter<TextForwardRef>,
479-
...props: NativePressableTextProps
480-
) = ({
481-
ref: forwardedRef,
482-
textProps,
483-
textPressabilityProps,
484-
}: {
482+
component PressableVirtualText(
485483
ref?: React.RefSetter<TextForwardRef>,
486-
...NativePressableTextProps,
487-
}) => {
484+
textProps: NativeTextProps,
485+
textPressabilityProps: TextPressabilityProps,
486+
) {
488487
const [isHighlighted, eventHandlersForText] = useTextPressability(
489488
textPressabilityProps,
490489
);
@@ -495,42 +494,40 @@ const NativePressableVirtualText: component(
495494
{...eventHandlersForText}
496495
isHighlighted={isHighlighted}
497496
isPressable={true}
498-
ref={forwardedRef}
497+
ref={ref}
499498
/>
500499
);
501-
};
500+
}
502501

503502
/**
504-
* Wrap the NativeText component and initialize pressability.
503+
* Wrap a NativeText component and initialize pressability.
505504
*
506505
* This logic is split out from the main Text component to enable the more
507506
* expensive pressability logic to be only initialized when needed.
508507
*/
509-
const NativePressableText: component(
510-
ref: React.RefSetter<TextForwardRef>,
511-
...props: NativePressableTextProps
512-
) = ({
513-
ref: forwardedRef,
514-
textProps,
515-
textPressabilityProps,
516-
}: {
508+
component PressableText(
517509
ref?: React.RefSetter<TextForwardRef>,
518-
...NativePressableTextProps,
519-
}) => {
510+
selectable?: ?boolean,
511+
textProps: NativeTextProps,
512+
textPressabilityProps: TextPressabilityProps,
513+
) {
520514
const [isHighlighted, eventHandlersForText] = useTextPressability(
521515
textPressabilityProps,
522516
);
523517

518+
const NativeComponent =
519+
selectable === true ? NativeSelectableText : NativeText;
520+
524521
return (
525-
<NativeText
522+
<NativeComponent
526523
{...textProps}
527524
{...eventHandlersForText}
528525
isHighlighted={isHighlighted}
529526
isPressable={true}
530-
ref={forwardedRef}
527+
ref={ref}
531528
/>
532529
);
533-
};
530+
}
534531

535532
const userSelectToSelectableMap = {
536533
auto: true,

packages/react-native/Libraries/Text/TextNativeComponent.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type {ProcessedColorValue} from '../StyleSheet/processColor';
1313
import type {GestureResponderEvent} from '../Types/CoreEventTypes';
1414
import type {TextProps} from './TextProps';
1515

16+
import {enablePreparedTextLayout} from '../../src/private/featureflags/ReactNativeFeatureFlags';
1617
import {createViewConfig} from '../NativeComponent/ViewConfig';
1718
import UIManager from '../ReactNative/UIManager';
1819
import createReactNativeComponentClass from '../Renderer/shims/createReactNativeComponentClass';
@@ -54,7 +55,7 @@ const textViewConfig = {
5455
},
5556
},
5657
uiViewClassName: 'RCTText',
57-
};
58+
} as const;
5859

5960
const virtualTextViewConfig = {
6061
validAttributes: {
@@ -63,7 +64,7 @@ const virtualTextViewConfig = {
6364
maxFontSizeMultiplier: true,
6465
},
6566
uiViewClassName: 'RCTVirtualText',
66-
};
67+
} as const;
6768

6869
/**
6970
* `NativeText` is an internal React Native host component, and is exported to
@@ -77,16 +78,22 @@ const virtualTextViewConfig = {
7778
// and <View> wrappers so that we no longer have any reason to export these APIs.
7879
export const NativeText: HostComponent<NativeTextProps> =
7980
(createReactNativeComponentClass('RCTText', () =>
80-
/* $FlowFixMe[incompatible-type] Natural Inference rollout. See
81-
* https://fburl.com/workplace/6291gfvu */
8281
createViewConfig(textViewConfig),
8382
): any);
8483

8584
export const NativeVirtualText: HostComponent<NativeTextProps> =
8685
!global.RN$Bridgeless && !UIManager.hasViewManagerConfig('RCTVirtualText')
8786
? NativeText
8887
: (createReactNativeComponentClass('RCTVirtualText', () =>
89-
/* $FlowFixMe[incompatible-type] Natural Inference rollout. See
90-
* https://fburl.com/workplace/6291gfvu */
9188
createViewConfig(virtualTextViewConfig),
9289
): any);
90+
91+
export const NativeSelectableText: HostComponent<NativeTextProps> =
92+
enablePreparedTextLayout()
93+
? (createReactNativeComponentClass('RCTSelectableText', () =>
94+
createViewConfig({
95+
...textViewConfig,
96+
uiViewClassName: 'RCTSelectableText',
97+
}),
98+
): any)
99+
: NativeText;

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/PreparedLayoutTextViewManager.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ internal class PreparedLayoutTextViewManager :
118118

119119
@ReactProp(name = "selectable", defaultBoolean = false)
120120
fun setSelectable(view: PreparedLayoutTextView, isSelectable: Boolean): Unit {
121-
// T222052152: Implement fine-grained text selection for PreparedLayoutTextView
122-
// view.setTextIsSelectable(isSelectable);
121+
check(!isSelectable) {
122+
"selectable Text should use SelectableTextViewManager instead of PreparedLayoutViewManager"
123+
}
123124
}
124125

125126
@ReactProp(name = "selectionColor", customType = "Color")

packages/react-native/ReactNativeApi.d.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<70e87b8481aeab750e8c747d9d4d28b1>>
7+
* @generated SignedSource<<4d9de6bc6082c3ea5b39b8a5b685ac68>>
88
*
99
* This file was generated by scripts/js-api/build-types/index.js.
1010
*/
@@ -321,6 +321,7 @@ declare const NativeModules: typeof NativeModules_default
321321
declare let NativeModules_default: {
322322
[moduleName: string]: any
323323
}
324+
declare const NativeSelectableText: HostComponent<NativeTextProps>
324325
declare const NativeText: HostComponent<NativeTextProps>
325326
declare const NativeTouchable:
326327
| typeof TouchableNativeFeedback
@@ -3366,6 +3367,7 @@ declare type NativeScrollVelocity = {
33663367
readonly x: number
33673368
readonly y: number
33683369
}
3370+
declare type NativeSelectableText = typeof NativeSelectableText
33693371
declare type NativeSwitchChangeEvent = {
33703372
readonly target: Int32
33713373
readonly value: boolean
@@ -5157,7 +5159,7 @@ declare type TextContentType =
51575159
| "URL"
51585160
| "username"
51595161
declare type TextForwardRef = React.ComponentRef<
5160-
typeof NativeText | typeof NativeVirtualText
5162+
typeof NativeSelectableText | typeof NativeText | typeof NativeVirtualText
51615163
>
51625164
declare type TextInput = typeof TextInput
51635165
declare type TextInputAndroidProps = {
@@ -5992,7 +5994,7 @@ export {
59925994
AlertOptions, // a0cdac0f
59935995
AlertType, // 5ab91217
59945996
AndroidKeyboardEvent, // e03becc8
5995-
Animated, // ed7eb912
5997+
Animated, // f39d3c6f
59965998
AppConfig, // ebddad4b
59975999
AppRegistry, // 6cdee1d6
59986000
AppState, // 12012be5
@@ -6212,7 +6214,7 @@ export {
62126214
TVViewPropsIOS, // 330ce7b5
62136215
TargetedEvent, // 16e98910
62146216
TaskProvider, // 266dedf2
6215-
Text, // e55ac2e2
6217+
Text, // 0620c789
62166218
TextContentType, // 239b3ecc
62176219
TextInput, // 2e89b91d
62186220
TextInputAndroidProps, // 3f09ce49

0 commit comments

Comments
 (0)