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

212 строки
6.0 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its 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 * as PressabilityDebug from '../Pressability/PressabilityDebug';
import usePressability from '../Pressability/usePressability';
import StyleSheet from '../StyleSheet/StyleSheet';
import processColor from '../StyleSheet/processColor';
import TextAncestor from './TextAncestor';
import {NativeText, NativeVirtualText} from './TextNativeComponent';
import {type TextProps} from './TextProps';
import * as React from 'react';
import {useContext, useMemo, useState} from 'react';
/**
* Text is the fundamental component for displaying text.
*
* @see https://reactnative.dev/docs/text
*/
const Text: React.AbstractComponent<
TextProps,
React.ElementRef<typeof NativeText | typeof NativeVirtualText>,
> = React.forwardRef((props: TextProps, forwardedRef) => {
const {
accessible,
allowFontScaling,
ellipsizeMode,
onLongPress,
onPress,
onPressIn,
onPressOut,
onResponderGrant,
onResponderMove,
onResponderRelease,
onResponderTerminate,
onResponderTerminationRequest,
onStartShouldSetResponder,
pressRetentionOffset,
suppressHighlighting,
...restProps
} = props;
const [isHighlighted, setHighlighted] = useState(false);
const isPressable =
(onPress != null ||
onLongPress != null ||
onStartShouldSetResponder != null) &&
restProps.disabled !== true;
const initialized = useLazyInitialization(isPressable);
const config = useMemo(
() =>
initialized
? {
disabled: !isPressable,
pressRectOffset: pressRetentionOffset,
onLongPress,
onPress,
onPressIn(event) {
setHighlighted(!suppressHighlighting);
onPressIn?.(event);
},
onPressOut(event) {
setHighlighted(false);
onPressOut?.(event);
},
onResponderTerminationRequest_DEPRECATED:
onResponderTerminationRequest,
onStartShouldSetResponder_DEPRECATED: onStartShouldSetResponder,
}
: null,
[
initialized,
isPressable,
pressRetentionOffset,
onLongPress,
onPress,
onPressIn,
onPressOut,
onResponderTerminationRequest,
onStartShouldSetResponder,
suppressHighlighting,
],
);
const eventHandlers = usePressability(config);
const eventHandlersForText = useMemo(
() =>
eventHandlers == null
? null
: {
onResponderGrant(event) {
eventHandlers.onResponderGrant(event);
if (onResponderGrant != null) {
onResponderGrant(event);
}
},
onResponderMove(event) {
eventHandlers.onResponderMove(event);
if (onResponderMove != null) {
onResponderMove(event);
}
},
onResponderRelease(event) {
eventHandlers.onResponderRelease(event);
if (onResponderRelease != null) {
onResponderRelease(event);
}
},
onResponderTerminate(event) {
eventHandlers.onResponderTerminate(event);
if (onResponderTerminate != null) {
onResponderTerminate(event);
}
},
onResponderTerminationRequest:
eventHandlers.onResponderTerminationRequest,
onStartShouldSetResponder: eventHandlers.onStartShouldSetResponder,
},
[
eventHandlers,
onResponderGrant,
onResponderMove,
onResponderRelease,
onResponderTerminate,
],
);
// TODO: Move this processing to the view configuration.
const selectionColor =
restProps.selectionColor == null
? null
: processColor(restProps.selectionColor);
let style = restProps.style;
if (__DEV__) {
if (PressabilityDebug.isEnabled() && onPress != null) {
style = StyleSheet.compose(restProps.style, {
color: 'magenta',
});
}
}
let numberOfLines = restProps.numberOfLines;
if (numberOfLines != null && !(numberOfLines >= 0)) {
console.error(
`'numberOfLines' in <Text> must be a non-negative number, received: ${numberOfLines}. The value will be set to 0.`,
);
numberOfLines = 0;
}
const hasTextAncestor = useContext(TextAncestor);
return hasTextAncestor ? (
<NativeVirtualText
{...restProps}
{...eventHandlersForText}
isHighlighted={isHighlighted}
isPressable={isPressable}
numberOfLines={numberOfLines}
selectionColor={selectionColor}
style={style}
ref={forwardedRef}
/>
) : (
<TextAncestor.Provider value={true}>
<NativeText
{...restProps}
{...eventHandlersForText}
accessible={accessible !== false}
allowFontScaling={allowFontScaling !== false}
ellipsizeMode={ellipsizeMode ?? 'tail'}
isHighlighted={isHighlighted}
numberOfLines={numberOfLines}
selectionColor={selectionColor}
style={style}
ref={forwardedRef}
/>
</TextAncestor.Provider>
);
});
Text.displayName = 'Text';
/**
* Switch to `deprecated-react-native-prop-types` for compatibility with future
* releases. This is deprecated and will be removed in the future.
*/
Text.propTypes = require('deprecated-react-native-prop-types').TextPropTypes;
/**
* 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.
*/
function useLazyInitialization(newValue: boolean): boolean {
const [oldValue, setValue] = useState(newValue);
if (!oldValue && newValue) {
setValue(newValue);
}
return oldValue;
}
module.exports = Text;