UNPKG

@cometchat/chat-uikit-react-native

Version:

Ready-to-use Chat UI Components for React Native

120 lines (118 loc) 4.78 kB
import React, { useCallback, useRef, useState } from "react"; import { Alert, Image, Linking, Platform, Text, View, } from "react-native"; import { localize } from "../../shared/resources/CometChatLocalize"; import { DefaultLinkPreview } from "./resources"; import { useTheme } from "../../theme"; /** * LinkPreviewBubble component displays a preview of a link with image, title, description, and favicon. * * @param props - LinkPreviewBubbleInterface properties. * @returns A JSX.Element rendering the link preview bubble. */ export const LinkPreviewBubble = (props) => { const { style, link, title, ChildView, image, onPress, description, favicon } = props; const theme = useTheme(); const _style = style; const [imageSource, setImageSource] = useState({ uri: image.startsWith("https:") ? image : `https:${image.split("http:")[1]}`, }); const [imageHeight, setImageHeight] = useState(); const [imageWidth, setImageWidth] = useState(); const [faviconSource, setFaviconSource] = useState({ uri: favicon.startsWith("https:") ? favicon : `https:${favicon.split("http:")[1]}`, }); const pressTime = useRef(0); /** * Records the time when the touch starts. */ const handleTouchStart = () => { pressTime.current = Date.now(); }; /** * Handles the touch end event. If the press duration is less than 500ms, it triggers the onPress callback or opens the link. */ const handleTouchEnd = async () => { if (pressTime.current === null && Platform.OS === "ios") return; const endTime = Date.now(); const pressDuration = endTime - (pressTime.current ?? 0); if (pressDuration < 500) { if (onPress) { onPress(); } else { const opened = await Linking.openURL(link); if (!opened) { Alert.alert(localize("SOMETHING_WRONG")); } } } }; /** * Handles the touch move event. For iOS, it cancels the press action. */ const onTouchMove = () => { if (Platform.OS === "ios") { pressTime.current = null; } }; /** * Callback for layout changes of the container. * Sets the image width and height based on the container size. * * @param event - The layout change event. */ const onLayoutHandler = useCallback((event) => { if (imageHeight && imageWidth) { return; } const containerWidth = event.nativeEvent.layout.width; Image.getSize(image, (width, height) => { setImageHeight(height); if (typeof style?.headerImageContainerStyle?.maxHeight === "number") { setImageHeight(height < style?.headerImageContainerStyle?.maxHeight ? height : style?.headerImageContainerStyle.maxHeight); } setImageWidth(width < containerWidth ? width : containerWidth); }, (error) => { console.log(error); }); }, [image, imageHeight, imageWidth, style]); return (<View style={{ flex: 1 }} onLayout={onLayoutHandler}> <View style={style?.headerImageContainerStyle} onTouchStart={handleTouchStart} onTouchEnd={handleTouchEnd} onTouchMove={onTouchMove}> <Image source={imageSource} style={[{ height: imageHeight, width: imageWidth }, style?.headerImageStyle]} onError={(err) => { setImageSource(DefaultLinkPreview); }}/> </View> <View style={style?.bodyStyle?.containerStyle}> <View style={{ flexDirection: "row" }}> <View style={style?.bodyStyle?.titleContainerStyle}> <Text style={style?.bodyStyle?.titleStyle} ellipsizeMode='tail'> {title} </Text> </View> <View style={style?.bodyStyle?.faviconContainerStyle}> <Image source={faviconSource} style={style?.bodyStyle?.faviconStyle} onError={(err) => { setImageSource(DefaultLinkPreview); }}/> </View> </View> <View style={style?.bodyStyle?.subtitleContainerStyle}> <Text style={style?.bodyStyle?.subtitleTitle} numberOfLines={2} ellipsizeMode='tail'> {description} </Text> <Text style={style?.bodyStyle?.subtitleTitle} numberOfLines={2} ellipsizeMode='tail'> {link} </Text> </View> </View> <View style={{ paddingVertical: theme.spacing.padding.p3, paddingHorizontal: style?.bodyStyle?.containerStyle.padding, }}> {ChildView && <ChildView />} </View> </View>); }; //# sourceMappingURL=LinkPreviewBubble.js.map