import React from "react"; import { parseTextMarkup, hasTextMarkup, type TextMarkupSegment } from "@/lib/text-markup"; import { cn } from "@/lib/utils"; interface MarkupTextProps { children: string; className?: string; as?: keyof React.JSX.IntrinsicElements; boldClassName?: string; strikeClassName?: string; } /** * Компонент для рендеринга текста с разметкой **bold** и ~~strike~~ * * Примеры использования: * Добро пожаловать в **WitLab**! * **50%** скидка только сегодня * Ваш **идеальный партнер** найден! */ export function MarkupText({ children, className, as: Component = "span", boldClassName = "font-bold", strikeClassName = "line-through" }: MarkupTextProps) { // Если текста нет, возвращаем пустой элемент if (!children || typeof children !== 'string') { return React.createElement(Component as string, { className }, children); } // Если нет разметки, возвращаем обычный текст if (!hasTextMarkup(children)) { return React.createElement(Component as string, { className }, children); } // Парсим разметку и рендерим сегменты const segments = parseTextMarkup(children); return React.createElement( Component as string, { className }, segments.map((segment: TextMarkupSegment, index: number) => { if (segment.type === 'bold') { return React.createElement( 'strong', { key: index, className: cn(boldClassName) }, segment.content ); } if (segment.type === 'strike') { return React.createElement( 'span', { key: index, className: cn(strikeClassName) }, segment.content ); } return React.createElement( React.Fragment, { key: index }, segment.content ); }) ); } /** * Хук для проверки наличия разметки в тексте */ export function useHasMarkup(text: string): boolean { return React.useMemo(() => hasTextMarkup(text), [text]); } /** * Компонент для превью разметки в админке */ export function MarkupPreview({ text }: { text: string }) { return (
Превью:
{text}
{hasTextMarkup(text) && (
💡 Разметка обнаружена: Текст в **двойных звездочках** — жирный, в ~~двойных тильдах~~ — зачёркнутый.
)}
); }