import React from 'react' import MessageFormatted from './MessageFormatted' import type { MessageFormatPart } from './chatUtils' /** * Map §-format color codes to Minecraft named colors. * Supports color codes (§0-§9, §a-§f) and formatting (§l, §o, §n, §m, §k, §r). */ const CODE_COLORS: Record = { '0': 'black', '1': 'dark_blue', '2': 'dark_green', '3': 'dark_aqua', '4': 'dark_red', '5': 'dark_purple', '6': 'gold', '7': 'gray', '8': 'dark_gray', '9': 'blue', 'a': 'green', 'b': 'aqua', 'c': 'red', 'd': 'light_purple','e': 'yellow', 'f': 'white', } function parseSectionCodes(text: string): MessageFormatPart[] { const parts: MessageFormatPart[] = [] const regex = /§([0-9a-fk-orA-FK-OR])|([^§]+)/g regex.lastIndex = 0 let color: string | undefined let bold = false, italic = false, underlined = false let strikethrough = false, obfuscated = false let match: RegExpExecArray | null while ((match = regex.exec(text)) !== null) { const code = match[1]?.toLowerCase() const chunk = match[2] if (code !== undefined) { if (CODE_COLORS[code]) { color = CODE_COLORS[code] bold = italic = underlined = strikethrough = obfuscated = false } else if (code === 'l') bold = true else if (code === 'o') italic = true else if (code === 'n') underlined = true else if (code === 'm') strikethrough = true else if (code === 'k') obfuscated = true else if (code === 'r') { color = undefined bold = italic = underlined = strikethrough = obfuscated = false } } else if (chunk) { parts.push({ text: chunk, color, bold, italic, underlined, strikethrough, obfuscated }) } } return parts } interface Props { text: string | undefined | null className?: string /** Wrap in a specific element; defaults to the MessageFormatted span wrapper */ fallbackColor?: string } /** * Renders a Minecraft text string that may contain §-formatting codes. * For plain strings without §, renders as a simple . * Used for inventory titles, tooltip names, and lore lines. */ export function MessageFormattedString({ text, className, fallbackColor }: Props) { if (!text) return null if (!text.includes('§')) { return ( {text} ) } const parts = parseSectionCodes(text) return }