diff --git a/packages/react-native/Libraries/Text/Text.js b/packages/react-native/Libraries/Text/Text.js index aef37d83b35..6713d1882b9 100644 --- a/packages/react-native/Libraries/Text/Text.js +++ b/packages/react-native/Libraries/Text/Text.js @@ -38,228 +38,153 @@ type TextForwardRef = React.ElementRef< const TextImpl: component( ref?: React.RefSetter, ...props: TextProps -) = 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; +) = ({ + ref: forwardedRef, + 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 +}: { + ref?: React.RefSetter, + ...TextProps, +}) => { + 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, - }; - } + 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 _accessibilityStateDisabled = _accessibilityState?.disabled; + const _disabled = disabled ?? _accessibilityStateDisabled; - const isPressable = - (onPress != null || - onLongPress != null || - onStartShouldSetResponder != null) && - _disabled !== true; + const isPressable = + (onPress != null || + onLongPress != null || + onStartShouldSetResponder != null) && + _disabled !== true; - // TODO: Move this processing to the view configuration. - const _selectionColor = - selectionColor != null ? processColor(selectionColor) : undefined; + // TODO: Move this processing to the view configuration. + const _selectionColor = + selectionColor != null ? processColor(selectionColor) : undefined; - let _style = style; + let _style = style; + if (__DEV__) { + if (PressabilityDebug.isEnabled() && onPress != null) { + _style = [style, {color: 'magenta'}]; + } + } + + let _numberOfLines = numberOfLines; + if (_numberOfLines != null && !(_numberOfLines >= 0)) { 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; - - let processedStyle = flattenStyle(_style); - if (processedStyle != null) { - let overrides: ?{...TextStyleInternal} = null; - if (typeof processedStyle.fontWeight === 'number') { - overrides = overrides || ({}: {...TextStyleInternal}); - overrides.fontWeight = - // $FlowFixMe[incompatible-cast] - (processedStyle.fontWeight.toString(): TextStyleInternal['fontWeight']); - } - - if (processedStyle.userSelect != null) { - _selectable = userSelectToSelectableMap[processedStyle.userSelect]; - overrides = overrides || ({}: {...TextStyleInternal}); - overrides.userSelect = undefined; - } - - if (processedStyle.verticalAlign != null) { - overrides = overrides || ({}: {...TextStyleInternal}); - overrides.textAlignVertical = - verticalAlignToTextAlignVerticalMap[processedStyle.verticalAlign]; - overrides.verticalAlign = undefined; - } - - if (overrides != null) { - // $FlowFixMe[incompatible-type] - _style = [_style, overrides]; - } - } - - const _nativeID = id ?? nativeID; - - const hasTextAncestor = useContext(TextAncestor); - if (hasTextAncestor) { - if (isPressable) { - return ( - - ); - } - - return ( - - {children} - + console.error( + `'numberOfLines' in must be a non-negative number, received: ${_numberOfLines}. The value will be set to 0.`, ); } + _numberOfLines = 0; + } - // 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}; + let _selectable = selectable; + + let processedStyle = flattenStyle(_style); + if (processedStyle != null) { + let overrides: ?{...TextStyleInternal} = null; + if (typeof processedStyle.fontWeight === 'number') { + overrides = overrides || ({}: {...TextStyleInternal}); + overrides.fontWeight = + // $FlowFixMe[incompatible-cast] + (processedStyle.fontWeight.toString(): TextStyleInternal['fontWeight']); } - const _accessible = Platform.select({ - ios: accessible !== false, - android: - accessible == null - ? onPress != null || onLongPress != null - : accessible, - default: accessible, - }); + if (processedStyle.userSelect != null) { + _selectable = userSelectToSelectableMap[processedStyle.userSelect]; + overrides = overrides || ({}: {...TextStyleInternal}); + overrides.userSelect = undefined; + } - let nativeText = null; + if (processedStyle.verticalAlign != null) { + overrides = overrides || ({}: {...TextStyleInternal}); + overrides.textAlignVertical = + verticalAlignToTextAlignVerticalMap[processedStyle.verticalAlign]; + overrides.verticalAlign = undefined; + } + + if (overrides != null) { + // $FlowFixMe[incompatible-type] + _style = [_style, overrides]; + } + } + + const _nativeID = id ?? nativeID; + + const hasTextAncestor = useContext(TextAncestor); + if (hasTextAncestor) { 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} + + {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} + ); +}; TextImpl.displayName = 'Text'; @@ -480,7 +477,14 @@ type NativePressableTextProps = $ReadOnly<{ const NativePressableVirtualText: component( ref: React.RefSetter, ...props: NativePressableTextProps -) = React.forwardRef(({textProps, textPressabilityProps}, forwardedRef) => { +) = ({ + ref: forwardedRef, + textProps, + textPressabilityProps, +}: { + ref?: React.RefSetter, + ...NativePressableTextProps, +}) => { const [isHighlighted, eventHandlersForText] = useTextPressability( textPressabilityProps, ); @@ -494,7 +498,7 @@ const NativePressableVirtualText: component( ref={forwardedRef} /> ); -}); +}; /** * Wrap the NativeText component and initialize pressability. @@ -505,7 +509,14 @@ const NativePressableVirtualText: component( const NativePressableText: component( ref: React.RefSetter, ...props: NativePressableTextProps -) = React.forwardRef(({textProps, textPressabilityProps}, forwardedRef) => { +) = ({ + ref: forwardedRef, + textProps, + textPressabilityProps, +}: { + ref?: React.RefSetter, + ...NativePressableTextProps, +}) => { const [isHighlighted, eventHandlersForText] = useTextPressability( textPressabilityProps, ); @@ -519,7 +530,7 @@ const NativePressableText: component( ref={forwardedRef} /> ); -}); +}; const userSelectToSelectableMap = { auto: true,