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
JavaScript
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