import type { ReactNode } from "react"; const URL = /(https?:\/\/[^\s]+)/g; const HTML_ENTITY = /&(?:#(\d+)|#x([\da-f]+)|amp|apos|gt|lt|quot);/gi; const NAMED_ENTITIES: Record = { "&": "&", "'": "'", ">": ">", "<": "<", """: '"', }; function decodeHtmlEntities(text: string): string { return text.replace(HTML_ENTITY, (entity, decimal, hexadecimal) => { if (!decimal && !hexadecimal) { return NAMED_ENTITIES[entity.toLowerCase()] ?? entity; } const codePoint = Number.parseInt(decimal ?? hexadecimal, decimal ? 10 : 16); return codePoint <= 0x10ffff ? String.fromCodePoint(codePoint) : entity; }); } function linkedText(text: string): ReactNode[] { const decoded = decodeHtmlEntities(text); const parts: ReactNode[] = []; let cursor = 0; for (const match of decoded.matchAll(URL)) { const href = match[0]; const start = match.index; if (start > cursor) parts.push(decoded.slice(cursor, start)); parts.push( {href} , ); cursor = start + href.length; } if (cursor < decoded.length) parts.push(decoded.slice(cursor)); return parts; } export function PostText({ text }: { text: string }) { return <>{linkedText(text)}; }