react-native-hyperlinks
Version:
A simple and customizable library to display hyperlinks in React Native
126 lines • 4.04 kB
JavaScript
import React from "react";
import { Linking, Text } from "react-native";
import linkifyIt from "linkify-it";
export default function Hyperlinks({ text, hyperlinkStyle, autoDetectMentions = true, autoDetectHastags = true, customHyperlinks = [], linkify = linkifyIt(), onLinkPress, onMentionPress, onHashtagPress, onCustomHyperlinkPress, style, ...textProps }) {
const matches = linkify.match(text) ?? [];
const detectedMentions = autoDetectMentions ? getMentions(text) : [];
const hashtags = autoDetectHastags ? getHashtags(text) : [];
if (matches.length === 0 &&
detectedMentions.length === 0 &&
hashtags.length === 0 &&
customHyperlinks.length === 0) {
return (<Text style={style} {...textProps}>
{text}
</Text>);
}
const allMatches = [];
function handleOnLinkPress(url) {
try {
if (onLinkPress) {
onLinkPress(url);
}
else {
Linking.openURL(url);
}
}
catch { }
}
matches.forEach((match) => {
allMatches.push({
start: match.index,
end: match.lastIndex,
onPress: () => match.raw.startsWith("@")
? onMentionPress?.(match.raw.replace("@", ""))
: handleOnLinkPress(match.url),
});
});
detectedMentions.forEach((mention) => {
allMatches.push({
start: mention.start,
end: mention.end,
onPress: () => {
onMentionPress?.(mention.username);
},
});
});
hashtags.forEach((hashtag) => {
allMatches.push({
start: hashtag.start,
end: hashtag.end,
onPress: () => {
onHashtagPress?.(hashtag.tag);
},
});
});
customHyperlinks.forEach((hyperlink) => {
allMatches.push({
start: hyperlink.start,
end: hyperlink.end,
onPress: () => onCustomHyperlinkPress?.(hyperlink),
});
});
const orderedMatches = allMatches.sort((a, b) => {
return a.start - b.start;
});
const chunks = [];
orderedMatches.forEach((match, index) => {
const isFirst = index === 0;
if (isFirst) {
if (match.start !== 0) {
chunks.push({
label: text.substring(0, match.start),
});
}
}
chunks.push({
label: text.substring(match.start, match.end),
onPress: match.onPress,
});
const hasNext = orderedMatches.length !== index + 1;
if (hasNext) {
chunks.push({
label: text.substring(match.end, orderedMatches[index + 1].start),
});
}
else {
const hasMoreText = text.length > match.end;
if (hasMoreText) {
chunks.push({
label: text.substring(match.end, text.length),
});
}
}
});
return (<Text style={style} {...textProps}>
{chunks.map((chunk, index) => (<Text onPress={chunk.onPress} style={[style, chunk.onPress ? hyperlinkStyle : {}]} key={index}>
{chunk.label}
</Text>))}
</Text>);
}
function getMentions(text) {
const mentionedUsers = [];
const regex = /\B@[a-zA-Z0-9_]+/gi;
let match;
while ((match = regex.exec(text)) != null) {
mentionedUsers.push({
username: match[0].replace("@", ""),
start: match.index,
end: match[0].length + match.index,
});
}
return mentionedUsers;
}
function getHashtags(text) {
const hashtags = [];
const regex = /\B#[a-zA-Z0-9_]+/gi;
let match;
while ((match = regex.exec(text)) != null) {
hashtags.push({
tag: match[0].replace("#", ""),
start: match.index,
end: match[0].length + match.index,
});
}
return hashtags;
}
//# sourceMappingURL=Hyperlinks.js.map