UNPKG

react-native-skia-responsive-text

Version:

A library providing a wrapper for the React Native Skia Text component, offering features like user-friendly text alignment, efficient multiline text management, and straightforward text truncation.

124 lines (120 loc) 4.93 kB
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } import { Group, Mask, Rect } from '@shopify/react-native-skia'; import { memo, useMemo } from 'react'; import { runOnJS, useDerivedValue } from 'react-native-reanimated'; import { useAnimatableValue } from '../hooks'; import { getTextChunks, getTextLinesAlignment, getVerticalAlignmentOffset, wrapText } from '../utils'; import TextLine from './TextLine'; const LINE_HEIGHT_MULTIPLIER = 1.5; function ResponsiveText(_ref) { let { animationSettings: animationSettingsProp, backgroundColor: backgroundColorProp, children, ellipsizeMode, font, height: heightProp, horizontalAlignment: horizontalAlignmentProp = 'left', lineHeight: lineHeightProp, numberOfLines, onMeasure, overflow = 'visible', text = '', verticalAlignment: verticalAlignmentProp = 'top', width: widthProp, x: xProp = 0, y: yProp = 0, ...rest } = _ref; const fontSize = font.getSize(); const width = widthProp ?? font.getTextWidth(text); // Update animation settings if they are provided const animationSettings = useMemo(() => { if (!animationSettingsProp) return undefined; const { duration, easing, onComplete } = animationSettingsProp; if (!duration && !easing) return undefined; if (!duration) return { easing, onComplete }; if (!easing) return { duration, onComplete }; return { duration, easing, onComplete }; }, [animationSettingsProp]); // Create shared values from animatable props const x = useAnimatableValue(xProp); const y = useAnimatableValue(yProp); const backgroundColor = useAnimatableValue(backgroundColorProp ?? 'transparent'); const lineHeight = useAnimatableValue(lineHeightProp ?? LINE_HEIGHT_MULTIPLIER * fontSize); const horizontalAlignment = useAnimatableValue(horizontalAlignmentProp); const verticalAlignment = useAnimatableValue(verticalAlignmentProp); const textChunks = useMemo(() => getTextChunks(text), [text]); // Divide text into lines const textLines = useMemo(() => wrapText(textChunks, font, width, numberOfLines, ellipsizeMode), [textChunks, font, width, numberOfLines, ellipsizeMode]); // Calculate remaining values const horizontalAlignmentOffsets = useDerivedValue(() => { const alignments = getTextLinesAlignment(textLines, width, horizontalAlignment.value); const textWidth = textLines.reduce((acc, _ref2) => { let { width: w } = _ref2; return Math.max(acc, w); }, 0); const textHeight = textLines.length * lineHeight.value; if (onMeasure) { runOnJS(onMeasure)(textWidth, textHeight); } return alignments; }, [textLines]); const textHeight = useDerivedValue(() => textLines.length * lineHeight.value - (lineHeight.value - LINE_HEIGHT_MULTIPLIER * fontSize)); const backgroundHeight = useDerivedValue(() => heightProp ?? textHeight.value); const verticalAlignmentOffset = useDerivedValue(() => getVerticalAlignmentOffset(textHeight.value, heightProp, verticalAlignment.value)); const backgroundComponent = backgroundColorProp && /*#__PURE__*/React.createElement(Rect, { color: backgroundColor, height: backgroundHeight, width: width, y: 0 }); const textComponent = /*#__PURE__*/React.createElement(React.Fragment, null, textLines.map((line, i) => /*#__PURE__*/React.createElement(TextLine, _extends({}, rest, { animationSettings: animationSettings, font: font, fontSize: fontSize, horizontalAlignmentOffsets: horizontalAlignmentOffsets, index: i, key: i, lineHeight: lineHeight, text: line.text, verticalAlignmentOffset: verticalAlignmentOffset }), children))); const maskElement = useMemo(() => /*#__PURE__*/React.createElement(Rect, { color: "white", height: backgroundHeight, width: width }), [backgroundHeight, width]); const groupTransform = useDerivedValue(() => [{ translateX: x.value }, { translateY: y.value }]); return /*#__PURE__*/React.createElement(Group, { transform: groupTransform }, overflow === 'hidden' ? /*#__PURE__*/React.createElement(React.Fragment, null, backgroundComponent && /*#__PURE__*/React.createElement(Mask, { mask: maskElement, mode: "luminance" }, backgroundComponent), /*#__PURE__*/React.createElement(Mask, { mask: maskElement, mode: "luminance" }, textComponent)) : /*#__PURE__*/React.createElement(React.Fragment, null, backgroundComponent, textComponent)); } export default /*#__PURE__*/memo(ResponsiveText); //# sourceMappingURL=ResponsiveText.js.map