/** * MessageText — rendert Chat-Text mit Auto-Linkifizierung: * - http(s)://... → tippbar, oeffnet im Browser * - mailto: oder plain E-Mail → tippbar, oeffnet Mail-App * - Telefonnummern → tippbar, oeffnet Android-Dialer * * Text ist durchgaengig markierbar/kopierbar (selectable). */ import React from 'react'; import { Text, Linking, TextStyle, StyleProp } from 'react-native'; // Regex kombiniert URL | Email | Telefonnummer. // Gruppenreihenfolge ist wichtig fuer die Erkennung unten. // // URL: http://... oder https://... bis zum ersten Whitespace / Anfuehrungszeichen. // Email: simpler Standard-Match (kein RFC-kompatibel aber gut genug). // Telefon: internationale Form (+49..., 0049..., 0176...), darf Leerzeichen // / Bindestriche / Schraegstriche / Klammern enthalten, mindestens 7 // Ziffern insgesamt. Vermeidet banale Zahlen (Uhrzeiten, Datum). const LINK_REGEX = new RegExp( '(https?:\\/\\/[^\\s<>"]+)' + // 1: URL '|([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,})' + // 2: Email '|((?:\\+|00)\\d[\\d\\s()\\-\\/]{6,}\\d|0\\d{2,4}[\\s\\/\\-]?[\\d\\s\\-\\/]{5,}\\d)', // 3: Telefon 'g', ); const LINK_STYLE = { color: '#0096FF', textDecorationLine: 'underline' } as TextStyle; interface Segment { text: string; kind: 'text' | 'url' | 'email' | 'phone'; } function tokenize(raw: string): Segment[] { const out: Segment[] = []; let lastEnd = 0; LINK_REGEX.lastIndex = 0; let m: RegExpExecArray | null; while ((m = LINK_REGEX.exec(raw)) !== null) { if (m.index > lastEnd) { out.push({ text: raw.slice(lastEnd, m.index), kind: 'text' }); } if (m[1]) out.push({ text: m[1], kind: 'url' }); else if (m[2]) out.push({ text: m[2], kind: 'email' }); else if (m[3]) out.push({ text: m[3], kind: 'phone' }); lastEnd = LINK_REGEX.lastIndex; } if (lastEnd < raw.length) out.push({ text: raw.slice(lastEnd), kind: 'text' }); return out; } function onPress(seg: Segment) { try { if (seg.kind === 'url') { Linking.openURL(seg.text); } else if (seg.kind === 'email') { Linking.openURL(`mailto:${seg.text}`); } else if (seg.kind === 'phone') { // Android-Dialer erwartet tel:-Schema ohne Leerzeichen/Bindestriche const clean = seg.text.replace(/[\s\-\/()]/g, ''); Linking.openURL(`tel:${clean}`); } } catch {} } interface Props { text: string; style?: StyleProp; } const MessageText: React.FC = ({ text, style }) => { const segments = React.useMemo(() => tokenize(text), [text]); return ( {segments.map((seg, i) => { if (seg.kind === 'text') { return {seg.text}; } return ( onPress(seg)}> {seg.text} ); })} ); }; export default MessageText;