UNPKG

react-native-modern-elements

Version:

A modern, customizable UI component library for React Native

66 lines (65 loc) 2.73 kB
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);