diff --git a/packages/react-native/Libraries/Text/Text.js b/packages/react-native/Libraries/Text/Text.js index 807b1c73d165e7..dbeb043e7b59c6 100644 --- a/packages/react-native/Libraries/Text/Text.js +++ b/packages/react-native/Libraries/Text/Text.js @@ -9,9 +9,9 @@ */ import type {PressEvent} from '../Types/CoreEventTypes'; -import type {TextProps} from './TextProps'; +import type {NativeTextProps} from './TextNativeComponent'; +import type {PressRetentionOffset, TextProps} from './TextProps'; -import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags'; import * as PressabilityDebug from '../Pressability/PressabilityDebug'; import usePressability from '../Pressability/usePressability'; import flattenStyle from '../StyleSheet/flattenStyle'; @@ -19,100 +19,356 @@ import processColor from '../StyleSheet/processColor'; import Platform from '../Utilities/Platform'; import TextAncestor from './TextAncestor'; import {NativeText, NativeVirtualText} from './TextNativeComponent'; -import TextOptimized from './TextOptimized'; import * as React from 'react'; import {useContext, useMemo, useState} from 'react'; +type TextForwardRef = React.ElementRef< + typeof NativeText | typeof NativeVirtualText, +>; + /** * Text is the fundamental component for displaying text. * * @see https://reactnative.dev/docs/text + * + * NOTE: This file is a short term fork of `Text` for the purpose of performance + * testing. Any changes to either this component or `Text` should be avoided + * while this file exists. + * + * Specific differences from `Text`: + * - Lazy init Pressability via a nested component + * - Skip children context wrapper when safe. + * - Move props destructuring to function param. */ -const TextLegacy: React.AbstractComponent< - TextProps, - React.ElementRef, -> = React.forwardRef((props: TextProps, forwardedRef) => { - const { - accessible, - accessibilityLabel, - accessibilityState, - allowFontScaling, - 'aria-busy': ariaBusy, - 'aria-checked': ariaChecked, - 'aria-disabled': ariaDisabled, - 'aria-expanded': ariaExpanded, - 'aria-label': ariaLabel, - 'aria-selected': ariaSelected, - ellipsizeMode, - disabled, - id, - nativeID, - numberOfLines, - onLongPress, - onPress, - onPressIn, - onPressOut, - onResponderGrant, - onResponderMove, - onResponderRelease, - onResponderTerminate, - onResponderTerminationRequest, - onStartShouldSetResponder, - pressRetentionOffset, - selectable, - selectionColor, - suppressHighlighting, - style, - ...restProps - } = props; - - const [isHighlighted, setHighlighted] = useState(false); +const Text: React.AbstractComponent = + React.forwardRef( + ( + { + accessible, + accessibilityLabel, + accessibilityState, + allowFontScaling, + 'aria-busy': ariaBusy, + 'aria-checked': ariaChecked, + 'aria-disabled': ariaDisabled, + 'aria-expanded': ariaExpanded, + 'aria-label': ariaLabel, + 'aria-selected': ariaSelected, + children, + ellipsizeMode, + disabled, + id, + nativeID, + numberOfLines, + onLongPress, + onPress, + onPressIn, + onPressOut, + onResponderGrant, + onResponderMove, + onResponderRelease, + onResponderTerminate, + onResponderTerminationRequest, + onStartShouldSetResponder, + pressRetentionOffset, + selectable, + selectionColor, + suppressHighlighting, + style, + ...restProps + }: TextProps, + forwardedRef, + ) => { + const _accessibilityLabel = ariaLabel ?? accessibilityLabel; + + let _accessibilityState: ?TextProps['accessibilityState'] = + accessibilityState; + if ( + ariaBusy != null || + ariaChecked != null || + ariaDisabled != null || + ariaExpanded != null || + ariaSelected != null + ) { + if (_accessibilityState != null) { + _accessibilityState = { + busy: ariaBusy ?? _accessibilityState.busy, + checked: ariaChecked ?? _accessibilityState.checked, + disabled: ariaDisabled ?? _accessibilityState.disabled, + expanded: ariaExpanded ?? _accessibilityState.expanded, + selected: ariaSelected ?? _accessibilityState.selected, + }; + } else { + _accessibilityState = { + busy: ariaBusy, + checked: ariaChecked, + disabled: ariaDisabled, + expanded: ariaExpanded, + selected: ariaSelected, + }; + } + } + + const _accessibilityStateDisabled = _accessibilityState?.disabled; + const _disabled = disabled ?? _accessibilityStateDisabled; + + const isPressable = + (onPress != null || + onLongPress != null || + onStartShouldSetResponder != null) && + _disabled !== true; + + // TODO: Move this processing to the view configuration. + const _selectionColor = + selectionColor == null ? null : processColor(selectionColor); + + let _style = style; + if (__DEV__) { + if (PressabilityDebug.isEnabled() && onPress != null) { + _style = [style, {color: 'magenta'}]; + } + } + + let _numberOfLines = numberOfLines; + if (_numberOfLines != null && !(_numberOfLines >= 0)) { + if (__DEV__) { + console.error( + `'numberOfLines' in must be a non-negative number, received: ${_numberOfLines}. The value will be set to 0.`, + ); + } + _numberOfLines = 0; + } + + let _selectable = selectable; + + const processedStyle = flattenStyle(_style); + if (processedStyle != null) { + if (typeof processedStyle.fontWeight === 'number') { + // $FlowFixMe[cannot-write] + processedStyle.fontWeight = processedStyle.fontWeight.toString(); + } + + if (processedStyle.userSelect != null) { + _selectable = userSelectToSelectableMap[processedStyle.userSelect]; + // $FlowFixMe[cannot-write] + delete processedStyle.userSelect; + } + + if (processedStyle.verticalAlign != null) { + // $FlowFixMe[cannot-write] + processedStyle.textAlignVertical = + verticalAlignToTextAlignVerticalMap[processedStyle.verticalAlign]; + // $FlowFixMe[cannot-write] + delete processedStyle.verticalAlign; + } + } + + const _nativeID = id ?? nativeID; + + const hasTextAncestor = useContext(TextAncestor); + if (hasTextAncestor) { + if (isPressable) { + return ( + + ); + } + + return ( + + {children} + + ); + } + + // If the disabled prop and accessibilityState.disabled are out of sync but not both in + // falsy states we need to update the accessibilityState object to use the disabled prop. + if ( + _disabled !== _accessibilityStateDisabled && + ((_disabled != null && _disabled !== false) || + (_accessibilityStateDisabled != null && + _accessibilityStateDisabled !== false)) + ) { + _accessibilityState = {..._accessibilityState, disabled: _disabled}; + } + + const _accessible = Platform.select({ + ios: accessible !== false, + android: + accessible == null + ? onPress != null || onLongPress != null + : accessible, + default: accessible, + }); + + let nativeText = null; + if (isPressable) { + nativeText = ( + + ); + } else { + nativeText = ( + + {children} + + ); + } + + if (children == null) { + return nativeText; + } + + // If the children do not contain a JSX element it would not be possible to have a + // nested `Text` component so we can skip adding the `TextAncestor` context wrapper + // which has a performance overhead. Since we do this for performance reasons we need + // to keep the check simple to avoid regressing overall perf. For this reason the + // `children.length` constant is set to `3`, this should be a reasonable tradeoff + // to capture the majority of `Text` uses but also not make this check too expensive. + if (Array.isArray(children) && children.length <= 3) { + let hasNonTextChild = false; + for (let child of children) { + if (child != null && typeof child === 'object') { + hasNonTextChild = true; + break; + } + } + if (!hasNonTextChild) { + return nativeText; + } + } else if (typeof children !== 'object') { + return nativeText; + } + + return ( + {nativeText} + ); + }, + ); - const _accessibilityLabel = ariaLabel ?? accessibilityLabel; - - let _accessibilityState: ?TextProps['accessibilityState'] = - accessibilityState; - if ( - ariaBusy != null || - ariaChecked != null || - ariaDisabled != null || - ariaExpanded != null || - ariaSelected != null - ) { - if (_accessibilityState != null) { - _accessibilityState = { - busy: ariaBusy ?? _accessibilityState.busy, - checked: ariaChecked ?? _accessibilityState.checked, - disabled: ariaDisabled ?? _accessibilityState.disabled, - expanded: ariaExpanded ?? _accessibilityState.expanded, - selected: ariaSelected ?? _accessibilityState.selected, - }; - } else { - _accessibilityState = { - busy: ariaBusy, - checked: ariaChecked, - disabled: ariaDisabled, - expanded: ariaExpanded, - selected: ariaSelected, - }; - } - } +Text.displayName = 'Text'; - const _accessibilityStateDisabled = _accessibilityState?.disabled; - const _disabled = disabled ?? _accessibilityStateDisabled; +type TextPressabilityProps = $ReadOnly<{ + onLongPress?: ?(event: PressEvent) => mixed, + onPress?: ?(event: PressEvent) => mixed, + onPressIn?: ?(event: PressEvent) => mixed, + onPressOut?: ?(event: PressEvent) => mixed, + onResponderGrant?: ?(event: PressEvent) => void, + onResponderMove?: ?(event: PressEvent) => void, + onResponderRelease?: ?(event: PressEvent) => void, + onResponderTerminate?: ?(event: PressEvent) => void, + onResponderTerminationRequest?: ?() => boolean, + onStartShouldSetResponder?: ?() => boolean, + pressRetentionOffset?: ?PressRetentionOffset, + suppressHighlighting?: ?boolean, +}>; - const isPressable = - (onPress != null || - onLongPress != null || - onStartShouldSetResponder != null) && - _disabled !== true; +/** + * Hook that handles setting up Pressability of Text components. + * + * NOTE: This hook is relatively expensive so it should only be used absolutely necessary. + */ +function useTextPressability({ + onLongPress, + onPress, + onPressIn, + onPressOut, + onResponderGrant, + onResponderMove, + onResponderRelease, + onResponderTerminate, + onResponderTerminationRequest, + onStartShouldSetResponder, + pressRetentionOffset, + suppressHighlighting, +}: TextPressabilityProps) { + const [isHighlighted, setHighlighted] = useState(false); - const initialized = useLazyInitialization(isPressable); + // Setup pressability config and wrap callbacks needs to track the highlight state. const config = useMemo(() => { - if (!initialized) { - return null; - } - let _onPressIn = onPressIn; let _onPressOut = onPressOut; @@ -132,7 +388,7 @@ const TextLegacy: React.AbstractComponent< } return { - disabled: !isPressable, + disabled: false, pressRectOffset: pressRetentionOffset, onLongPress, onPress, @@ -140,8 +396,6 @@ const TextLegacy: React.AbstractComponent< onPressOut: _onPressOut, }; }, [ - initialized, - isPressable, pressRetentionOffset, onLongPress, onPress, @@ -150,7 +404,10 @@ const TextLegacy: React.AbstractComponent< suppressHighlighting, ]); + // Init the pressability class const eventHandlers = usePressability(config); + + // Create NativeText event handlers which proxy events to pressability const eventHandlersForText = useMemo( () => eventHandlers == null @@ -201,128 +458,67 @@ const TextLegacy: React.AbstractComponent< ], ); - // TODO: Move this processing to the view configuration. - const _selectionColor = - selectionColor == null ? null : processColor(selectionColor); - - let _style = style; - if (__DEV__) { - if (PressabilityDebug.isEnabled() && onPress != null) { - _style = [style, {color: 'magenta'}]; - } - } + // Return the highlight state and NativeText event handlers + return useMemo( + () => [isHighlighted, eventHandlersForText], + [isHighlighted, eventHandlersForText], + ); +} - let _numberOfLines = numberOfLines; - if (_numberOfLines != null && !(_numberOfLines >= 0)) { - if (__DEV__) { - console.error( - `'numberOfLines' in must be a non-negative number, received: ${_numberOfLines}. The value will be set to 0.`, - ); - } - _numberOfLines = 0; - } - - let _selectable = selectable; - const processedStyle = flattenStyle(_style); - if (processedStyle != null) { - if (typeof processedStyle.fontWeight === 'number') { - // $FlowFixMe[cannot-write] - processedStyle.fontWeight = processedStyle.fontWeight.toString(); - } +type NativePressableTextProps = $ReadOnly<{ + textProps: NativeTextProps, + textPressabilityProps: TextPressabilityProps, +}>; - if (processedStyle.userSelect != null) { - _selectable = userSelectToSelectableMap[processedStyle.userSelect]; - // $FlowFixMe[cannot-write] - delete processedStyle.userSelect; - } - - if (processedStyle.verticalAlign != null) { - // $FlowFixMe[cannot-write] - processedStyle.textAlignVertical = - verticalAlignToTextAlignVerticalMap[processedStyle.verticalAlign]; - // $FlowFixMe[cannot-write] - delete processedStyle.verticalAlign; - } - } - - const _nativeID = id ?? nativeID; - - const hasTextAncestor = useContext(TextAncestor); - if (hasTextAncestor) { - return ( - - ); - } - - // If the disabled prop and accessibilityState.disabled are out of sync but not both in - // falsy states we need to update the accessibilityState object to use the disabled prop. - if ( - _disabled !== _accessibilityStateDisabled && - ((_disabled != null && _disabled !== false) || - (_accessibilityStateDisabled != null && - _accessibilityStateDisabled !== false)) - ) { - _accessibilityState = {..._accessibilityState, disabled: _disabled}; - } - - const _accessible = Platform.select({ - ios: accessible !== false, - android: - accessible == null ? onPress != null || onLongPress != null : accessible, - default: accessible, - }); +/** + * Wrap the NativeVirtualText component and initialize pressability. + * + * This logic is split out from the main Text component to enable the more + * expensive pressability logic to be only initialized when needed. + */ +const NativePressableVirtualText: React.AbstractComponent< + NativePressableTextProps, + TextForwardRef, +> = React.forwardRef(({textProps, textPressabilityProps}, forwardedRef) => { + const [isHighlighted, eventHandlersForText] = useTextPressability( + textPressabilityProps, + ); return ( - - - + ); }); -TextLegacy.displayName = 'TextLegacy'; - /** - * Returns false until the first time `newValue` is true, after which this will - * always return true. This is necessary to lazily initialize `Pressability` so - * we do not eagerly create one for every pressable `Text` component. + * Wrap the NativeText component and initialize pressability. + * + * This logic is split out from the main Text component to enable the more + * expensive pressability logic to be only initialized when needed. */ -function useLazyInitialization(newValue: boolean): boolean { - const [oldValue, setValue] = useState(newValue); - if (!oldValue && newValue) { - setValue(newValue); - } - return oldValue; -} +const NativePressableText: React.AbstractComponent< + NativePressableTextProps, + TextForwardRef, +> = React.forwardRef(({textProps, textPressabilityProps}, forwardedRef) => { + const [isHighlighted, eventHandlersForText] = useTextPressability( + textPressabilityProps, + ); + + return ( + + ); +}); const userSelectToSelectableMap = { auto: true, @@ -339,17 +535,4 @@ const verticalAlignToTextAlignVerticalMap = { middle: 'center', }; -const Text: React.AbstractComponent< - TextProps, - React.ElementRef, -> = React.forwardRef((props: TextProps, forwardedRef) => { - if (ReactNativeFeatureFlags.shouldUseOptimizedText()) { - return ; - } else { - return ; - } -}); - -Text.displayName = 'Text'; - module.exports = Text; diff --git a/packages/react-native/Libraries/Text/TextOptimized.js b/packages/react-native/Libraries/Text/TextOptimized.js deleted file mode 100644 index 615badd9ad6758..00000000000000 --- a/packages/react-native/Libraries/Text/TextOptimized.js +++ /dev/null @@ -1,538 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ - -import type {PressEvent} from '../Types/CoreEventTypes'; -import type {NativeTextProps} from './TextNativeComponent'; -import type {PressRetentionOffset, TextProps} from './TextProps'; - -import * as PressabilityDebug from '../Pressability/PressabilityDebug'; -import usePressability from '../Pressability/usePressability'; -import flattenStyle from '../StyleSheet/flattenStyle'; -import processColor from '../StyleSheet/processColor'; -import Platform from '../Utilities/Platform'; -import TextAncestor from './TextAncestor'; -import {NativeText, NativeVirtualText} from './TextNativeComponent'; -import * as React from 'react'; -import {useContext, useMemo, useState} from 'react'; - -type TextForwardRef = React.ElementRef< - typeof NativeText | typeof NativeVirtualText, ->; - -/** - * Text is the fundamental component for displaying text. - * - * @see https://reactnative.dev/docs/text - * - * NOTE: This file is a short term fork of `Text` for the purpose of performance - * testing. Any changes to either this component or `Text` should be avoided - * while this file exists. - * - * Specific differences from `Text`: - * - Lazy init Pressability via a nested component - * - Skip children context wrapper when safe. - * - Move props destructuring to function param. - */ -const TextOptimized: React.AbstractComponent = - React.forwardRef( - ( - { - accessible, - accessibilityLabel, - accessibilityState, - allowFontScaling, - 'aria-busy': ariaBusy, - 'aria-checked': ariaChecked, - 'aria-disabled': ariaDisabled, - 'aria-expanded': ariaExpanded, - 'aria-label': ariaLabel, - 'aria-selected': ariaSelected, - children, - ellipsizeMode, - disabled, - id, - nativeID, - numberOfLines, - onLongPress, - onPress, - onPressIn, - onPressOut, - onResponderGrant, - onResponderMove, - onResponderRelease, - onResponderTerminate, - onResponderTerminationRequest, - onStartShouldSetResponder, - pressRetentionOffset, - selectable, - selectionColor, - suppressHighlighting, - style, - ...restProps - }: TextProps, - forwardedRef, - ) => { - const _accessibilityLabel = ariaLabel ?? accessibilityLabel; - - let _accessibilityState: ?TextProps['accessibilityState'] = - accessibilityState; - if ( - ariaBusy != null || - ariaChecked != null || - ariaDisabled != null || - ariaExpanded != null || - ariaSelected != null - ) { - if (_accessibilityState != null) { - _accessibilityState = { - busy: ariaBusy ?? _accessibilityState.busy, - checked: ariaChecked ?? _accessibilityState.checked, - disabled: ariaDisabled ?? _accessibilityState.disabled, - expanded: ariaExpanded ?? _accessibilityState.expanded, - selected: ariaSelected ?? _accessibilityState.selected, - }; - } else { - _accessibilityState = { - busy: ariaBusy, - checked: ariaChecked, - disabled: ariaDisabled, - expanded: ariaExpanded, - selected: ariaSelected, - }; - } - } - - const _accessibilityStateDisabled = _accessibilityState?.disabled; - const _disabled = disabled ?? _accessibilityStateDisabled; - - const isPressable = - (onPress != null || - onLongPress != null || - onStartShouldSetResponder != null) && - _disabled !== true; - - // TODO: Move this processing to the view configuration. - const _selectionColor = - selectionColor == null ? null : processColor(selectionColor); - - let _style = style; - if (__DEV__) { - if (PressabilityDebug.isEnabled() && onPress != null) { - _style = [style, {color: 'magenta'}]; - } - } - - let _numberOfLines = numberOfLines; - if (_numberOfLines != null && !(_numberOfLines >= 0)) { - if (__DEV__) { - console.error( - `'numberOfLines' in must be a non-negative number, received: ${_numberOfLines}. The value will be set to 0.`, - ); - } - _numberOfLines = 0; - } - - let _selectable = selectable; - - const processedStyle = flattenStyle(_style); - if (processedStyle != null) { - if (typeof processedStyle.fontWeight === 'number') { - // $FlowFixMe[cannot-write] - processedStyle.fontWeight = processedStyle.fontWeight.toString(); - } - - if (processedStyle.userSelect != null) { - _selectable = userSelectToSelectableMap[processedStyle.userSelect]; - // $FlowFixMe[cannot-write] - delete processedStyle.userSelect; - } - - if (processedStyle.verticalAlign != null) { - // $FlowFixMe[cannot-write] - processedStyle.textAlignVertical = - verticalAlignToTextAlignVerticalMap[processedStyle.verticalAlign]; - // $FlowFixMe[cannot-write] - delete processedStyle.verticalAlign; - } - } - - const _nativeID = id ?? nativeID; - - const hasTextAncestor = useContext(TextAncestor); - if (hasTextAncestor) { - if (isPressable) { - return ( - - ); - } - - return ( - - {children} - - ); - } - - // If the disabled prop and accessibilityState.disabled are out of sync but not both in - // falsy states we need to update the accessibilityState object to use the disabled prop. - if ( - _disabled !== _accessibilityStateDisabled && - ((_disabled != null && _disabled !== false) || - (_accessibilityStateDisabled != null && - _accessibilityStateDisabled !== false)) - ) { - _accessibilityState = {..._accessibilityState, disabled: _disabled}; - } - - const _accessible = Platform.select({ - ios: accessible !== false, - android: - accessible == null - ? onPress != null || onLongPress != null - : accessible, - default: accessible, - }); - - let nativeText = null; - if (isPressable) { - nativeText = ( - - ); - } else { - nativeText = ( - - {children} - - ); - } - - if (children == null) { - return nativeText; - } - - // If the children do not contain a JSX element it would not be possible to have a - // nested `Text` component so we can skip adding the `TextAncestor` context wrapper - // which has a performance overhead. Since we do this for performance reasons we need - // to keep the check simple to avoid regressing overall perf. For this reason the - // `children.length` constant is set to `3`, this should be a reasonable tradeoff - // to capture the majority of `Text` uses but also not make this check too expensive. - if (Array.isArray(children) && children.length <= 3) { - let hasNonTextChild = false; - for (let child of children) { - if (child != null && typeof child === 'object') { - hasNonTextChild = true; - break; - } - } - if (!hasNonTextChild) { - return nativeText; - } - } else if (typeof children !== 'object') { - return nativeText; - } - - return ( - {nativeText} - ); - }, - ); - -TextOptimized.displayName = 'TextOptimized'; - -type TextPressabilityProps = $ReadOnly<{ - onLongPress?: ?(event: PressEvent) => mixed, - onPress?: ?(event: PressEvent) => mixed, - onPressIn?: ?(event: PressEvent) => mixed, - onPressOut?: ?(event: PressEvent) => mixed, - onResponderGrant?: ?(event: PressEvent) => void, - onResponderMove?: ?(event: PressEvent) => void, - onResponderRelease?: ?(event: PressEvent) => void, - onResponderTerminate?: ?(event: PressEvent) => void, - onResponderTerminationRequest?: ?() => boolean, - onStartShouldSetResponder?: ?() => boolean, - pressRetentionOffset?: ?PressRetentionOffset, - suppressHighlighting?: ?boolean, -}>; - -/** - * Hook that handles setting up Pressability of Text components. - * - * NOTE: This hook is relatively expensive so it should only be used absolutely necessary. - */ -function useTextPressability({ - onLongPress, - onPress, - onPressIn, - onPressOut, - onResponderGrant, - onResponderMove, - onResponderRelease, - onResponderTerminate, - onResponderTerminationRequest, - onStartShouldSetResponder, - pressRetentionOffset, - suppressHighlighting, -}: TextPressabilityProps) { - const [isHighlighted, setHighlighted] = useState(false); - - // Setup pressability config and wrap callbacks needs to track the highlight state. - const config = useMemo(() => { - let _onPressIn = onPressIn; - let _onPressOut = onPressOut; - - // Updating isHighlighted causes unnecessary re-renders for platforms that don't use it - // in the best case, and cause issues with text selection in the worst case. Forcing - // the isHighlighted prop to false on all platforms except iOS. - if (Platform.OS === 'ios') { - _onPressIn = (event: PressEvent) => { - setHighlighted(suppressHighlighting == null || !suppressHighlighting); - onPressIn?.(event); - }; - - _onPressOut = (event: PressEvent) => { - setHighlighted(false); - onPressOut?.(event); - }; - } - - return { - disabled: false, - pressRectOffset: pressRetentionOffset, - onLongPress, - onPress, - onPressIn: _onPressIn, - onPressOut: _onPressOut, - }; - }, [ - pressRetentionOffset, - onLongPress, - onPress, - onPressIn, - onPressOut, - suppressHighlighting, - ]); - - // Init the pressability class - const eventHandlers = usePressability(config); - - // Create NativeText event handlers which proxy events to pressability - const eventHandlersForText = useMemo( - () => - eventHandlers == null - ? null - : { - onResponderGrant(event: PressEvent) { - eventHandlers.onResponderGrant(event); - if (onResponderGrant != null) { - onResponderGrant(event); - } - }, - onResponderMove(event: PressEvent) { - eventHandlers.onResponderMove(event); - if (onResponderMove != null) { - onResponderMove(event); - } - }, - onResponderRelease(event: PressEvent) { - eventHandlers.onResponderRelease(event); - if (onResponderRelease != null) { - onResponderRelease(event); - } - }, - onResponderTerminate(event: PressEvent) { - eventHandlers.onResponderTerminate(event); - if (onResponderTerminate != null) { - onResponderTerminate(event); - } - }, - onClick: eventHandlers.onClick, - onResponderTerminationRequest: - onResponderTerminationRequest != null - ? onResponderTerminationRequest - : eventHandlers.onResponderTerminationRequest, - onStartShouldSetResponder: - onStartShouldSetResponder != null - ? onStartShouldSetResponder - : eventHandlers.onStartShouldSetResponder, - }, - [ - eventHandlers, - onResponderGrant, - onResponderMove, - onResponderRelease, - onResponderTerminate, - onResponderTerminationRequest, - onStartShouldSetResponder, - ], - ); - - // Return the highlight state and NativeText event handlers - return useMemo( - () => [isHighlighted, eventHandlersForText], - [isHighlighted, eventHandlersForText], - ); -} - -type NativePressableTextProps = $ReadOnly<{ - textProps: NativeTextProps, - textPressabilityProps: TextPressabilityProps, -}>; - -/** - * Wrap the NativeVirtualText component and initialize pressability. - * - * This logic is split out from the main Text component to enable the more - * expensive pressability logic to be only initialized when needed. - */ -const NativePressableVirtualText: React.AbstractComponent< - NativePressableTextProps, - TextForwardRef, -> = React.forwardRef(({textProps, textPressabilityProps}, forwardedRef) => { - const [isHighlighted, eventHandlersForText] = useTextPressability( - textPressabilityProps, - ); - - return ( - - ); -}); - -/** - * Wrap the NativeText component and initialize pressability. - * - * This logic is split out from the main Text component to enable the more - * expensive pressability logic to be only initialized when needed. - */ -const NativePressableText: React.AbstractComponent< - NativePressableTextProps, - TextForwardRef, -> = React.forwardRef(({textProps, textPressabilityProps}, forwardedRef) => { - const [isHighlighted, eventHandlersForText] = useTextPressability( - textPressabilityProps, - ); - - return ( - - ); -}); - -const userSelectToSelectableMap = { - auto: true, - text: true, - none: false, - contain: true, - all: true, -}; - -const verticalAlignToTextAlignVerticalMap = { - auto: 'auto', - top: 'top', - bottom: 'bottom', - middle: 'center', -}; - -module.exports = TextOptimized; diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index 7ff79dfe92a296..00392c37415517 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -8083,10 +8083,10 @@ exports[`public API should not change unintentionally Libraries/StyleSheet/split `; exports[`public API should not change unintentionally Libraries/Text/Text.js 1`] = ` -"declare const Text: React.AbstractComponent< - TextProps, - React.ElementRef, +"type TextForwardRef = React.ElementRef< + typeof NativeText | typeof NativeVirtualText, >; +declare const Text: React.AbstractComponent; declare module.exports: Text; " `; @@ -8110,15 +8110,6 @@ declare export const NativeVirtualText: HostComponent; " `; -exports[`public API should not change unintentionally Libraries/Text/TextOptimized.js 1`] = ` -"type TextForwardRef = React.ElementRef< - typeof NativeText | typeof NativeVirtualText, ->; -declare const TextOptimized: React.AbstractComponent; -declare module.exports: TextOptimized; -" -`; - exports[`public API should not change unintentionally Libraries/Text/TextProps.js 1`] = ` "export type PressRetentionOffset = $ReadOnly<{ top: number, diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 90d1b47734aefb..a7a54fb73674e3 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -197,10 +197,6 @@ const definitions: FeatureFlagDefinitions = { description: 'Enables use of AnimatedObject for animating transform values.', }, - shouldUseOptimizedText: { - defaultValue: false, - description: 'Use optimized version of component.', - }, shouldUseRemoveClippedSubviewsAsDefaultOnIOS: { defaultValue: false, description: diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index b82772a7da50b2..3ae6c920bcf124 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<84a8c1caff585fd164111b4954624d74>> * @flow strict-local */ @@ -32,7 +32,6 @@ export type ReactNativeFeatureFlagsJsOnly = { enableAccessToHostTreeInFabric: Getter, isLayoutAnimationEnabled: Getter, shouldUseAnimatedObjectForTransform: Getter, - shouldUseOptimizedText: Getter, shouldUseRemoveClippedSubviewsAsDefaultOnIOS: Getter, shouldUseSetNativePropsInFabric: Getter, }; @@ -100,11 +99,6 @@ export const isLayoutAnimationEnabled: Getter = createJavaScriptFlagGet */ export const shouldUseAnimatedObjectForTransform: Getter = createJavaScriptFlagGetter('shouldUseAnimatedObjectForTransform', false); -/** - * Use optimized version of component. - */ -export const shouldUseOptimizedText: Getter = createJavaScriptFlagGetter('shouldUseOptimizedText', false); - /** * removeClippedSubviews prop will be used as the default in FlatList on iOS to match Android */