plazbot
Version:
Official Plazbot SDK for creating AI agents for WhatsApp, portals, and developers.
130 lines (129 loc) • 5.33 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useMemo } from 'react';
import { usePlazbotContext } from '../../context/PlazbotContext';
function tokenize(text) {
const tokens = [];
const lines = text.split('\n');
let i = 0;
while (i < lines.length) {
const line = lines[i];
// Bloque de codigo
if (line.trimStart().startsWith('```')) {
const lang = line.trimStart().slice(3).trim();
const codeLines = [];
i++;
while (i < lines.length && !lines[i].trimStart().startsWith('```')) {
codeLines.push(lines[i]);
i++;
}
tokens.push({ type: 'codeblock', content: codeLines.join('\n'), language: lang || undefined });
i++;
continue;
}
// Heading
const headingMatch = line.match(/^(#{1,3})\s+(.+)/);
if (headingMatch) {
tokens.push({ type: 'heading', content: headingMatch[2], level: headingMatch[1].length });
i++;
continue;
}
// Lista
const listMatch = line.match(/^[\s]*[-*]\s+(.+)/);
if (listMatch) {
tokens.push({ type: 'listitem', content: listMatch[1] });
i++;
continue;
}
// Lista numerada
const numListMatch = line.match(/^[\s]*\d+\.\s+(.+)/);
if (numListMatch) {
tokens.push({ type: 'listitem', content: numListMatch[1] });
i++;
continue;
}
// Linea vacia
if (line.trim() === '') {
tokens.push({ type: 'br', content: '' });
i++;
continue;
}
// Texto con inline formatting
tokens.push({ type: 'text', content: line });
i++;
}
return tokens;
}
function renderInline(text, theme) {
const result = [];
// Patron: bold, italic, code, links
const regex = /(\*\*(.+?)\*\*)|(\*(.+?)\*)|(`([^`]+?)`)|(\[(.+?)\]\((.+?)\))/g;
let lastIndex = 0;
let match;
let key = 0;
while ((match = regex.exec(text)) !== null) {
// Texto antes del match
if (match.index > lastIndex) {
result.push(text.slice(lastIndex, match.index));
}
if (match[2]) {
// Bold
result.push(_jsx("strong", { children: match[2] }, key++));
}
else if (match[4]) {
// Italic
result.push(_jsx("em", { children: match[4] }, key++));
}
else if (match[6]) {
// Inline code
result.push(_jsx("code", { style: {
backgroundColor: 'rgba(0,0,0,0.06)',
padding: '2px 6px',
borderRadius: '4px',
fontSize: '0.9em',
fontFamily: 'monospace',
}, children: match[6] }, key++));
}
else if (match[8] && match[9]) {
// Link
result.push(_jsx("a", { href: match[9], target: "_blank", rel: "noopener noreferrer", style: { color: theme.primaryColor, textDecoration: 'underline' }, children: match[8] }, key++));
}
lastIndex = match.index + match[0].length;
}
if (lastIndex < text.length) {
result.push(text.slice(lastIndex));
}
return result.length > 0 ? result : [text];
}
export function MarkdownRenderer({ content, className, style }) {
const { theme } = usePlazbotContext();
const elements = useMemo(() => {
const tokens = tokenize(content);
return tokens.map((token, i) => {
switch (token.type) {
case 'heading': {
const fontSize = token.level === 1 ? '1.3em' : token.level === 2 ? '1.15em' : '1.05em';
return (_jsx("div", { style: { fontSize, fontWeight: 600, margin: '8px 0 4px' }, children: renderInline(token.content, theme) }, i));
}
case 'codeblock':
return (_jsx("pre", { style: {
backgroundColor: 'rgba(0,0,0,0.06)',
padding: '12px',
borderRadius: '6px',
overflow: 'auto',
fontSize: '0.85em',
fontFamily: 'monospace',
margin: '8px 0',
whiteSpace: 'pre-wrap',
wordBreak: 'break-word',
}, children: _jsx("code", { children: token.content }) }, i));
case 'listitem':
return (_jsxs("div", { style: { display: 'flex', gap: '8px', margin: '2px 0', paddingLeft: '4px' }, children: [_jsx("span", { style: { color: theme.textSecondary }, children: "\u2022" }), _jsx("span", { children: renderInline(token.content, theme) })] }, i));
case 'br':
return _jsx("div", { style: { height: '8px' } }, i);
default:
return (_jsx("div", { style: { margin: '2px 0', lineHeight: 1.6 }, children: renderInline(token.content, theme) }, i));
}
});
}, [content, theme]);
return (_jsx("div", { className: className, style: { wordBreak: 'break-word', ...style }, children: elements }));
}