react-native-modern-elements
Version:
A modern, customizable UI component library for React Native
66 lines (65 loc) • 2.73 kB
JavaScript
import React, { memo, useCallback, useState } from "react";
import { StyleSheet, Text, TouchableOpacity, View, } from "react-native";
import Animated, { useAnimatedStyle, useSharedValue, withTiming, } from "react-native-reanimated";
const ExpandableText = ({ children, numberOfLines = 4, textStyle, readMoreStyle, }) => {
const [expanded, setExpanded] = useState(false);
const [isTruncated, setIsTruncated] = useState(false);
const [measured, setMeasured] = useState(false);
const height = useSharedValue(0);
const [fullHeight, setFullHeight] = useState(0);
const [collapsedHeight, setCollapsedHeight] = useState(0);
// Measure text and determine truncation
const handleTextLayout = useCallback((e) => {
if (measured)
return;
const { lines } = e.nativeEvent;
if (lines.length > numberOfLines)
setIsTruncated(true);
const totalHeight = lines.reduce((acc, line) => acc + line.height, 0);
setFullHeight(totalHeight);
const collapsed = lines
.slice(0, numberOfLines)
.reduce((acc, line) => acc + line.height, 0);
setCollapsedHeight(collapsed);
height.value = collapsed; // initial height
setMeasured(true);
}, [measured, numberOfLines, height]);
const toggleExpand = useCallback(() => {
setExpanded((prev) => !prev);
height.value = withTiming(expanded ? collapsedHeight : fullHeight, {
duration: 330,
});
}, [expanded, collapsedHeight, fullHeight, height]);
const animatedStyle = useAnimatedStyle(() => ({
height: height.value,
overflow: "hidden",
}));
return (React.createElement(View, null,
React.createElement(TouchableOpacity, { onPress: toggleExpand, activeOpacity: 0.5 },
React.createElement(Animated.View, { style: animatedStyle },
React.createElement(Text, { onTextLayout: handleTextLayout, style: [styles.text, textStyle] }, children))),
isTruncated && (React.createElement(TouchableOpacity, { onPress: toggleExpand },
React.createElement(Text, { style: [
styles.readMore,
expanded && styles.readLess,
readMoreStyle,
] }, expanded ? "Read Less....⏫" : "Read More...⬇️")))));
};
const styles = StyleSheet.create({
text: {
fontSize: 14,
color: "#333",
lineHeight: 20,
},
readMore: {
fontSize: 14,
fontWeight: "bold",
color: "black",
marginTop: 2,
textDecorationLine: "underline",
},
readLess: {
textDecorationLine: "none",
},
});
export default memo(ExpandableText);