@ai-react-markdown/core 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx","../src/context.tsx","../src/defs.ts","../src/preprocessors/latex.ts","../src/preprocessors/index.ts","../src/components/MarkdownContent.tsx","../src/hooks/useStableValue.ts","../src/components/typography/Default.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo, memo } from 'react';\nimport AIMarkdownRenderStateProvider, { AIMarkdownRenderStateProviderProps } from './context';\nimport { AIMDContentPreprocessor } from './preprocessors/defs';\nimport preprocessAIMDContent from './preprocessors';\nimport AIMarkdownContent from './components/MarkdownContent';\nimport { Components } from 'react-markdown';\nimport {\n AIMarkdownRenderConfig,\n AIMarkdownMetadata,\n AIMarkdownTypographyComponent,\n AIMarkdownExtraStyleComponent,\n AIMarkdownVariant,\n AIMarkdownColorScheme,\n} from './defs';\nimport useStableValue from './hooks/useStableValue';\nimport DefaultTypography from './components/typography/Default';\n\nexport interface AIMarkdownProps<\n TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig,\n TRenderData extends AIMarkdownMetadata = AIMarkdownMetadata,\n> extends Omit<AIMarkdownRenderStateProviderProps<TConfig, TRenderData>, 'fontSize'> {\n fontSize?: number | string;\n content: string;\n contentPreprocessors?: AIMDContentPreprocessor[];\n customComponents?: Components;\n typography?: AIMarkdownTypographyComponent;\n extraStyle?: AIMarkdownExtraStyleComponent;\n variant?: AIMarkdownVariant;\n colorScheme?: AIMarkdownColorScheme;\n}\n\nconst AIMarkdownComponent = <\n TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig,\n TRenderData extends AIMarkdownMetadata = AIMarkdownMetadata,\n>({\n streaming = false,\n content,\n fontSize,\n contentPreprocessors,\n customComponents,\n config,\n metadata,\n typography: Typography = DefaultTypography,\n extraStyle: ExtraStyle,\n variant = 'default',\n colorScheme = 'light',\n}: AIMarkdownProps<TConfig, TRenderData>) => {\n const usedFontSize = fontSize ? (typeof fontSize === 'number' ? `${fontSize}px` : fontSize) : '0.875rem';\n\n const stableConfig = useStableValue(config);\n const stablePreprocessors = useStableValue(contentPreprocessors);\n const stableCustomComponents = useStableValue(customComponents);\n\n const usedContent = useMemo(\n () => (content ? preprocessAIMDContent(content, stablePreprocessors) : content),\n [content, stablePreprocessors]\n );\n\n return (\n <AIMarkdownRenderStateProvider<TConfig, TRenderData>\n streaming={streaming}\n fontSize={usedFontSize}\n config={stableConfig}\n metadata={metadata}\n >\n <Typography fontSize={usedFontSize} variant={variant} colorScheme={colorScheme}>\n {ExtraStyle ? (\n <ExtraStyle>\n <AIMarkdownContent content={usedContent} customComponents={stableCustomComponents} />\n </ExtraStyle>\n ) : (\n <AIMarkdownContent content={usedContent} customComponents={stableCustomComponents} />\n )}\n </Typography>\n </AIMarkdownRenderStateProvider>\n );\n};\n\nconst AIMarkdown = memo(AIMarkdownComponent);\nAIMarkdown.displayName = 'AIMarkdown';\n\nexport default AIMarkdown as typeof AIMarkdownComponent;\n\n// Types\nexport type { AIMDContentPreprocessor };\nexport type {\n AIMarkdownRenderConfig,\n AIMarkdownRenderState,\n AIMarkdownMetadata,\n AIMarkdownTypographyProps,\n AIMarkdownTypographyComponent,\n AIMarkdownExtraStyleProps,\n AIMarkdownExtraStyleComponent,\n AIMarkdownVariant,\n AIMarkdownColorScheme,\n} from './defs';\n\n// Enums\nexport { AIMarkdownRenderExtraSyntax, AIMarkdownRenderDisplayOptimizeAbility } from './defs';\n\n// Hook — for custom components to access render state\nexport { useAIMarkdownRenderState } from './context';\n","import { PropsWithChildren, createContext, useContext, useMemo } from 'react';\nimport cloneDeep from 'lodash/cloneDeep';\nimport mergeWith from 'lodash/mergeWith';\nimport {\n AIMarkdownRenderConfig,\n AIMarkdownMetadata,\n AIMarkdownRenderState,\n defaultMRMarkdownRenderConfig,\n} from './defs';\nimport { DeepPartial } from './utils/ts-util';\n\nconst AIMarkdownRenderStateContext = createContext<AIMarkdownRenderState<\n AIMarkdownRenderConfig,\n AIMarkdownMetadata\n> | null>(null);\n\nexport function useAIMarkdownRenderState<\n TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig,\n TMetadata extends AIMarkdownMetadata = AIMarkdownMetadata,\n>() {\n const context = useContext(AIMarkdownRenderStateContext) as AIMarkdownRenderState<TConfig, TMetadata>;\n\n if (!context) {\n throw new Error('useAIMarkdownRenderState must be used within an <AIMarkdown /> component.');\n }\n\n return context;\n}\n\nexport interface AIMarkdownRenderStateProviderProps<\n TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig,\n TMetadata extends AIMarkdownMetadata = AIMarkdownMetadata,\n> extends PropsWithChildren {\n streaming: boolean;\n fontSize: string;\n config?: DeepPartial<TConfig>;\n metadata?: TMetadata;\n}\n\n/**\n * When merging config, arrays from the source (user config) should fully replace\n * the target (default config) instead of being merged by index.\n */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nconst configMergeCustomizer = (\n _objValue: any,\n srcValue: any,\n _key: string,\n _object: any,\n _source: any,\n _stack: any\n) => {\n if (Array.isArray(srcValue)) {\n return srcValue;\n }\n};\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\nconst AIMarkdownRenderStateProvider = <\n RCT extends AIMarkdownRenderConfig = AIMarkdownRenderConfig,\n RDT extends AIMarkdownMetadata = AIMarkdownMetadata,\n>({\n streaming,\n fontSize,\n config,\n metadata,\n children,\n}: AIMarkdownRenderStateProviderProps<RCT, RDT>) => {\n const mergedConfig = useMemo(\n () =>\n config\n ? mergeWith(cloneDeep(defaultMRMarkdownRenderConfig), config, configMergeCustomizer)\n : defaultMRMarkdownRenderConfig,\n [config]\n );\n\n const state = useMemo(\n () => ({\n streaming,\n fontSize,\n config: mergedConfig,\n metadata,\n }),\n [streaming, fontSize, mergedConfig, metadata]\n );\n\n return <AIMarkdownRenderStateContext.Provider value={state}>{children}</AIMarkdownRenderStateContext.Provider>;\n};\n\nexport default AIMarkdownRenderStateProvider;\n","import { ComponentType, PropsWithChildren } from 'react';\n\nexport enum AIMarkdownRenderExtraSyntax {\n HIGHLIGHT = 'HIGHLIGHT', // support ==Highlight==\n DEFINITION_LIST = 'DEFINITION_LIST', // support Definition List https://michelf.ca/projects/php-markdown/extra/#def-list\n SUBSCRIPT = 'SUBSCRIPT', // support superscript and subscript\n}\n\nexport enum AIMarkdownRenderDisplayOptimizeAbility {\n REMOVE_COMMENTS = 'REMOVE_COMMENTS', // remove comments\n SMARTYPANTS = 'SMARTYPANTS', // make conent more typographic by SmartyPants https://www.npmjs.com/package/smartypants\n PANGU = 'PANGU', // auto add space between CJK and English\n}\n\nexport interface AIMarkdownRenderConfig {\n extraSyntaxSupported: AIMarkdownRenderExtraSyntax[];\n displayOptimizeAbilities: AIMarkdownRenderDisplayOptimizeAbility[];\n}\n\nexport const defaultMRMarkdownRenderConfig: AIMarkdownRenderConfig = {\n extraSyntaxSupported: [\n AIMarkdownRenderExtraSyntax.HIGHLIGHT,\n AIMarkdownRenderExtraSyntax.DEFINITION_LIST,\n AIMarkdownRenderExtraSyntax.SUBSCRIPT,\n ],\n displayOptimizeAbilities: [\n AIMarkdownRenderDisplayOptimizeAbility.REMOVE_COMMENTS,\n AIMarkdownRenderDisplayOptimizeAbility.SMARTYPANTS,\n AIMarkdownRenderDisplayOptimizeAbility.PANGU,\n ],\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface AIMarkdownMetadata extends Record<string, any> {}\n\nexport type AIMarkdownVariant = 'default' | (string & {});\nexport type AIMarkdownColorScheme = 'light' | 'dark' | (string & {});\n\nexport interface AIMarkdownTypographyProps extends PropsWithChildren {\n fontSize: string;\n variant?: AIMarkdownVariant;\n colorScheme?: AIMarkdownColorScheme;\n}\nexport type AIMarkdownTypographyComponent = ComponentType<AIMarkdownTypographyProps>;\n\nexport interface AIMarkdownExtraStyleProps extends PropsWithChildren {}\nexport type AIMarkdownExtraStyleComponent = ComponentType<AIMarkdownExtraStyleProps>;\n\nexport interface AIMarkdownRenderState<\n TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig,\n TMetadata extends AIMarkdownMetadata = AIMarkdownMetadata,\n> {\n streaming: boolean;\n fontSize: string;\n config: TConfig;\n metadata?: TMetadata;\n}\n","/**\n * LaTeX preprocess functions\n * Thanks the implementations from the following repositories:\n * - https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n * - https://github.com/danny-avila/LibreChat/blob/main/client/src/utils/latex.ts\n */\n\n/**\n * Escape mhchem commands in LaTeX expressions to ensure proper rendering.\n *\n * @param text Input string containing LaTeX expressions with mhchem commands\n * @returns String with escaped mhchem commands\n * @from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction escapeMhchemCommands(text: string) {\n return text.replaceAll('$\\\\ce{', '$\\\\\\\\ce{').replaceAll('$\\\\pu{', '$\\\\\\\\pu{');\n}\n\n/**\n * Efficiently finds all code block regions in the content\n * @param content The content to analyze\n * @returns Array of code block regions [start, end]\n * @from https://github.com/danny-avila/LibreChat/blob/main/client/src/utils/latex.ts\n */\nfunction findCodeBlockRegions(content: string): Array<[number, number]> {\n const regions: Array<[number, number]> = [];\n let inlineStart = -1;\n let multilineStart = -1;\n\n for (let i = 0; i < content.length; i++) {\n const char = content[i];\n\n // Check for multiline code blocks\n if (char === '`' && i + 2 < content.length && content[i + 1] === '`' && content[i + 2] === '`') {\n if (multilineStart === -1) {\n multilineStart = i;\n i += 2; // Skip the next two backticks\n } else {\n regions.push([multilineStart, i + 2]);\n multilineStart = -1;\n i += 2;\n }\n }\n // Check for inline code blocks (only if not in multiline)\n else if (char === '`' && multilineStart === -1) {\n if (inlineStart === -1) {\n inlineStart = i;\n } else {\n regions.push([inlineStart, i]);\n inlineStart = -1;\n }\n }\n }\n\n return regions;\n}\n\n/**\n * Checks if a position is inside any code block region using binary search\n * @param position The position to check\n * @param codeRegions Array of code block regions\n * @returns True if position is inside a code block\n * @from https://github.com/danny-avila/LibreChat/blob/main/client/src/utils/latex.ts\n */\nfunction isInCodeBlock(position: number, codeRegions: Array<[number, number]>): boolean {\n let left = 0;\n let right = codeRegions.length - 1;\n\n while (left <= right) {\n const mid = Math.floor((left + right) / 2);\n const [start, end] = codeRegions[mid];\n\n if (position >= start && position <= end) {\n return true;\n } else if (position < start) {\n right = mid - 1;\n } else {\n left = mid + 1;\n }\n }\n\n return false;\n}\n\nconst CURRENCY_REGEX = /(?<![\\\\$])\\$(?!\\$)(?=\\d+(?:,\\d{3})*(?:\\.\\d+)?(?:[KMBkmb])?(?:\\s|$|[^a-zA-Z\\d]))/g;\nconst NO_ESCAPED_DOLLAR_REGEX = /(?<![\\\\$])\\$(?!\\$)/g;\nconst DELIMITERS_REGEX = /\\\\\\[([\\S\\s]*?[^\\\\])\\\\]|\\\\\\((.*?)\\\\\\)/g;\nconst UNESCAPED_PIPES_REGEX = /(?<!\\\\)\\|/g;\nconst LATEX_BLOCK_REGEX = /\\$\\$([\\S\\s]*?)\\$\\$|(?<![\\\\$])\\$(?!\\$)((?:.|\\n)*?)(?<![\\\\`])\\$(?!\\$)/g;\nconst ESCAPE_TEXT_UNDERSCORES_REGEX = /\\\\text{([^}]*)}/g;\nconst SINGLE_DOLLAR_REGEX = /(?<![\\\\$])\\$(?!\\$)((?:[^$\\n]|\\\\[$])+?)(?<!\\\\)(?<!`)\\$(?!\\$)/g;\n\n/**\n * Convert LaTeX bracket delimiters to dollar sign delimiters.\n * Converts \\[...\\] to $$...$$ and \\(...\\) to $...$\n * Preserves code blocks during conversion.\n *\n * @param text Input string containing LaTeX expressions\n * @returns String with LaTeX bracket delimiters converted to dollar sign delimiters\n * @modified from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction convertLatexDelimiters(text: string, codeRegions: Array<[number, number]>): string {\n return text.replaceAll(\n DELIMITERS_REGEX,\n (match: string, squareBracket: string | undefined, roundBracket: string | undefined, index: number): string => {\n if (isInCodeBlock(index, codeRegions)) {\n return match;\n }\n if (squareBracket !== undefined) {\n return `$$${squareBracket}$$`;\n } else if (roundBracket !== undefined) {\n return `$${roundBracket}$`;\n }\n return match;\n }\n );\n}\n\n/**\n * Helper function: replace unescaped pipes with \\vert in LaTeX math fragments\n * @from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nconst replaceUnescapedPipes = (formula: string): string =>\n // Use \\vert{} so the control sequence terminates before the next token\n formula.replaceAll(UNESCAPED_PIPES_REGEX, '\\\\vert{}');\n/**\n * Escape pipes in LaTeX expressions to prevent them from being interpreted as\n * column separators in markdown tables.\n *\n * @param text Input string containing LaTeX expressions\n * @returns String with pipes escaped in LaTeX expressions\n * @modified from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction escapeLatexPipes(text: string, codeRegions: Array<[number, number]>): string {\n // Replace unescaped '|' with '\\vert' within LaTeX math ranges so that\n // remark-gfm table parsing doesn't treat them as column separators.\n // Keep code blocks/inline code unchanged.\n return text.replaceAll(LATEX_BLOCK_REGEX, (match, display, inline, index) => {\n if (isInCodeBlock(index, codeRegions)) {\n return match;\n }\n if (display !== undefined) return `$$${replaceUnescapedPipes(display)}$$`;\n if (inline !== undefined) return `$${replaceUnescapedPipes(inline)}$`;\n return match;\n });\n}\n\n/**\n * Escape unescaped underscores within \\text{...} commands in LaTeX expressions.\n * For example, \\text{node_domain} becomes \\text{node\\_domain},\n * but \\text{node\\_domain} remains \\text{node\\_domain}.\n *\n * @param text Input string that may contain LaTeX expressions\n * @returns String with unescaped underscores escaped within \\text{...} commands\n * @modified from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction escapeTextUnderscores(text: string, codeRegions: Array<[number, number]>): string {\n return text.replaceAll(ESCAPE_TEXT_UNDERSCORES_REGEX, (match, textContent: string, index: number) => {\n if (isInCodeBlock(index, codeRegions)) {\n return match;\n }\n // textContent is the content within the braces, e.g., \"node_domain\" or \"already\\_escaped\"\n // Replace '_' with '\\_' only when the underscore '_' is not preceded by a backslash '\\'.\n // (?<!\\\\) is a negative lookbehind assertion that ensures the character before '_' is not '\\'.\n const escapedTextContent = textContent.replaceAll(/(?<!\\\\)_/g, '\\\\_');\n return `\\\\text{${escapedTextContent}}`;\n });\n}\n\nexport function preprocessLaTeX(str: string): string {\n // Step 0: return early if no LaTeX patterns are found\n if (!str.includes('$') && !str.includes('\\\\[') && !str.includes('\\\\(')) return str;\n\n let processed = str;\n\n // Step 1: escape mhchem commands\n processed = escapeMhchemCommands(processed);\n\n // Step 2: find code block regions\n const codeRegions = findCodeBlockRegions(processed);\n\n // Step 3: escape currency dollar signs\n const parts = [];\n let lastIndex = 0;\n const currencyMatchesIterator = processed.matchAll(CURRENCY_REGEX);\n const currencyMatches = Array.from(currencyMatchesIterator);\n for (let i = 0; i < currencyMatches.length; i++) {\n const match = currencyMatches[i];\n parts.push(processed.substring(lastIndex, match.index));\n let needEscape = true;\n if (!isInCodeBlock(match.index, codeRegions)) {\n let restBeforeNextMatchOrEnd = '';\n if (i < currencyMatches.length - 1) {\n const nextMatch = currencyMatches[i + 1];\n if (nextMatch.index - match.index > 1) {\n restBeforeNextMatchOrEnd = processed.substring(match.index + 1, nextMatch.index);\n }\n } else {\n restBeforeNextMatchOrEnd = processed.substring(match.index + 1, processed.length);\n }\n const firstLineBeforeNextMatch = restBeforeNextMatchOrEnd.split(/\\r\\n|\\r|\\n/g)[0];\n if (Array.from(firstLineBeforeNextMatch.matchAll(NO_ESCAPED_DOLLAR_REGEX)).length % 2 !== 0) {\n const previousNewCotent = parts.join('');\n const previousLastLineContent = previousNewCotent.split(/\\r\\n|\\r|\\n/g).pop();\n const wholeLineBeforeNextMatchWithoutCurrentDollar = previousLastLineContent + firstLineBeforeNextMatch;\n if (\n Array.from(wholeLineBeforeNextMatchWithoutCurrentDollar.matchAll(NO_ESCAPED_DOLLAR_REGEX)).length % 2 !==\n 0\n ) {\n needEscape = false;\n }\n }\n } else {\n needEscape = false;\n }\n parts.push(needEscape ? '\\\\$' : '$');\n lastIndex = match.index + 1;\n }\n parts.push(processed.substring(lastIndex));\n processed = parts.join('');\n console.log('processed', processed);\n\n // Step 4: convert LaTeX delimiters\n processed = convertLatexDelimiters(processed, codeRegions);\n\n // Step 5: escape LaTeX pipes\n processed = escapeLatexPipes(processed, codeRegions);\n\n // Step 6: escape text underscores\n processed = escapeTextUnderscores(processed, codeRegions);\n\n // Step 7: convert single dollar delimiters to double dollars\n const result: string[] = [];\n lastIndex = 0;\n const singleDollarMatchesIterator = processed.matchAll(SINGLE_DOLLAR_REGEX);\n for (const match of singleDollarMatchesIterator) {\n if (!isInCodeBlock(match.index, codeRegions)) {\n result.push(processed.substring(lastIndex, match.index));\n result.push(`$$${match[1]}$$`);\n lastIndex = match.index + match[0].length;\n }\n }\n result.push(processed.substring(lastIndex));\n\n return result.join('');\n}\n","import { AIMDContentPreprocessor } from './defs';\nimport { preprocessLaTeX } from './latex';\n\nfunction applyPreprocessors(value: string, ...fns: Array<AIMDContentPreprocessor>): string {\n return fns.reduce((result, fn) => fn(result), value);\n}\n\nconst defaultExtraPreprocessors: AIMDContentPreprocessor[] = [];\n\nexport default function preprocessAIMDContent(\n content: string,\n extraPreprocessors: AIMDContentPreprocessor[] = defaultExtraPreprocessors\n) {\n return applyPreprocessors(content, preprocessLaTeX, ...extraPreprocessors);\n}\n","import { memo, useMemo } from 'react';\nimport ReactMarkdown, { Components } from 'react-markdown';\nimport rehypeKatex from 'rehype-katex';\nimport rehypeRaw from 'rehype-raw';\nimport rehypeUnwrapImages from 'rehype-unwrap-images';\nimport rehypeSanitize, { defaultSchema } from 'rehype-sanitize';\nimport remarkBreaks from 'remark-breaks';\nimport remarkCjkFriendly from 'remark-cjk-friendly';\nimport remarkCjkFriendlyGfmStrikethrough from 'remark-cjk-friendly-gfm-strikethrough';\nimport remarkEmoji from 'remark-emoji';\nimport remarkGfm from 'remark-gfm';\nimport remarkMath from 'remark-math';\nimport { remarkDefinitionList, defListHastHandlers } from 'remark-definition-list';\nimport remarkSupersub from 'remark-supersub';\nimport { remarkMark as remarkMarkHighlight } from 'remark-mark-highlight';\nimport remarkSqueezeParagraphs from 'remark-squeeze-paragraphs';\nimport remarkSmartypants from 'remark-smartypants';\nimport remarkPangu from 'remark-pangu';\nimport remarkRemoveComments from 'remark-remove-comments';\nimport { useAIMarkdownRenderState } from '../context';\nimport { AIMarkdownRenderDisplayOptimizeAbility, AIMarkdownRenderExtraSyntax } from '../defs';\n\nconst DisplayOptimizeRemarkPluginMap = {\n [AIMarkdownRenderDisplayOptimizeAbility.REMOVE_COMMENTS]: remarkRemoveComments,\n [AIMarkdownRenderDisplayOptimizeAbility.SMARTYPANTS]: remarkSmartypants,\n [AIMarkdownRenderDisplayOptimizeAbility.PANGU]: remarkPangu,\n};\n\nconst ExtraSyntaxRemarkPluginMap = {\n [AIMarkdownRenderExtraSyntax.HIGHLIGHT]: remarkMarkHighlight,\n [AIMarkdownRenderExtraSyntax.DEFINITION_LIST]: remarkDefinitionList,\n [AIMarkdownRenderExtraSyntax.SUBSCRIPT]: remarkSupersub,\n};\n\nconst DefaultCustomComponents: Components = {};\n\ninterface AIMarkdownContentProps {\n content: string;\n customComponents?: Components;\n}\n\nconst AIMarkdownContent = memo(({ content, customComponents }: AIMarkdownContentProps) => {\n const { config } = useAIMarkdownRenderState();\n\n const { extraSyntaxRemarkPlugins, enableDefinitionList } = useMemo(\n () => ({\n extraSyntaxRemarkPlugins: config.extraSyntaxSupported.map((syntax) => ExtraSyntaxRemarkPluginMap[syntax]),\n enableDefinitionList: config.extraSyntaxSupported.includes(AIMarkdownRenderExtraSyntax.DEFINITION_LIST),\n }),\n [config.extraSyntaxSupported]\n );\n\n const displayOptimizeRemarkPlugins = useMemo(() => {\n return config.displayOptimizeAbilities.map((ability) => DisplayOptimizeRemarkPluginMap[ability]);\n }, [config.displayOptimizeAbilities]);\n\n const usedComponents = useMemo(() => {\n return customComponents ? { ...DefaultCustomComponents, ...customComponents } : DefaultCustomComponents;\n }, [customComponents]);\n\n return (\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n [\n remarkMath,\n {\n singleDollarTextMath: false,\n },\n ],\n ...extraSyntaxRemarkPlugins,\n remarkBreaks,\n remarkEmoji,\n remarkSqueezeParagraphs,\n remarkCjkFriendly,\n remarkCjkFriendlyGfmStrikethrough,\n ...displayOptimizeRemarkPlugins,\n ]}\n rehypePlugins={[\n [\n rehypeRaw,\n {\n passThrough: [],\n },\n ],\n [\n rehypeSanitize,\n {\n ...defaultSchema,\n tagNames: [...(defaultSchema.tagNames || []), 'mark'],\n attributes: {\n ...defaultSchema.attributes,\n // The `language-*` regex is allowed by default.\n code: [['className', /^language-./, 'math-inline', 'math-display']],\n },\n },\n ],\n rehypeKatex,\n rehypeUnwrapImages,\n ]}\n remarkRehypeOptions={{\n allowDangerousHtml: true,\n handlers: {\n ...(enableDefinitionList ? defListHastHandlers : {}),\n },\n }}\n components={usedComponents}\n // By default, the defaultUrlTransform function in Windows environments treats local paths, such as those starting with C:/, as unsafe and replaces them with an empty string. Hence, in this case, it simply returns the URL that it has identified without any modification.\n // urlTransform={(url: string) => url}\n >\n {content}\n </ReactMarkdown>\n );\n});\n\nAIMarkdownContent.displayName = 'AIMarkdownContent';\n\nexport default AIMarkdownContent;\n","import { useRef, useEffect } from 'react';\nimport isEqual from 'lodash/isEqual';\n\nexport default function useStableValue<T>(value: T): T {\n const ref = useRef(value);\n\n // eslint-disable-next-line react-hooks/refs\n const prev = ref.current;\n const stableValue = isEqual(prev, value) ? prev : value;\n\n useEffect(() => {\n ref.current = stableValue;\n }, [stableValue]);\n\n return stableValue;\n}\n","import { memo } from 'react';\nimport type { AIMarkdownTypographyProps } from '../../defs';\n\nconst DefaultTypography = memo(({ children, fontSize, variant, colorScheme }: AIMarkdownTypographyProps) => (\n <div\n className={`aim-typography-root ${variant ?? ''} ${colorScheme ?? ''}`.trim()}\n style={{ width: '100%', fontSize }}\n >\n {children}\n </div>\n));\n\nDefaultTypography.displayName = 'DefaultTypography';\n\nexport default DefaultTypography;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,IAAAA,gBAA8B;;;ACF9B,mBAAsE;AACtE,uBAAsB;AACtB,uBAAsB;;;ACAf,IAAK,8BAAL,kBAAKC,iCAAL;AACL,EAAAA,6BAAA,eAAY;AACZ,EAAAA,6BAAA,qBAAkB;AAClB,EAAAA,6BAAA,eAAY;AAHF,SAAAA;AAAA,GAAA;AAML,IAAK,yCAAL,kBAAKC,4CAAL;AACL,EAAAA,wCAAA,qBAAkB;AAClB,EAAAA,wCAAA,iBAAc;AACd,EAAAA,wCAAA,WAAQ;AAHE,SAAAA;AAAA,GAAA;AAWL,IAAM,gCAAwD;AAAA,EACnE,sBAAsB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,0BAA0B;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ADwDS;AA3ET,IAAM,mCAA+B,4BAG3B,IAAI;AAEP,SAAS,2BAGZ;AACF,QAAM,cAAU,yBAAW,4BAA4B;AAEvD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,2EAA2E;AAAA,EAC7F;AAEA,SAAO;AACT;AAiBA,IAAM,wBAAwB,CAC5B,WACA,UACA,MACA,SACA,SACA,WACG;AACH,MAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,WAAO;AAAA,EACT;AACF;AAGA,IAAM,gCAAgC,CAGpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAoD;AAClD,QAAM,mBAAe;AAAA,IACnB,MACE,aACI,iBAAAC,aAAU,iBAAAC,SAAU,6BAA6B,GAAG,QAAQ,qBAAqB,IACjF;AAAA,IACN,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,YAAQ;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,WAAW,UAAU,cAAc,QAAQ;AAAA,EAC9C;AAEA,SAAO,4CAAC,6BAA6B,UAA7B,EAAsC,OAAO,OAAQ,UAAS;AACxE;AAEA,IAAO,kBAAQ;;;AE3Ef,SAAS,qBAAqB,MAAc;AAC1C,SAAO,KAAK,WAAW,UAAU,UAAU,EAAE,WAAW,UAAU,UAAU;AAC9E;AAQA,SAAS,qBAAqB,SAA0C;AACtE,QAAM,UAAmC,CAAC;AAC1C,MAAI,cAAc;AAClB,MAAI,iBAAiB;AAErB,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,OAAO,QAAQ,CAAC;AAGtB,QAAI,SAAS,OAAO,IAAI,IAAI,QAAQ,UAAU,QAAQ,IAAI,CAAC,MAAM,OAAO,QAAQ,IAAI,CAAC,MAAM,KAAK;AAC9F,UAAI,mBAAmB,IAAI;AACzB,yBAAiB;AACjB,aAAK;AAAA,MACP,OAAO;AACL,gBAAQ,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;AACpC,yBAAiB;AACjB,aAAK;AAAA,MACP;AAAA,IACF,WAES,SAAS,OAAO,mBAAmB,IAAI;AAC9C,UAAI,gBAAgB,IAAI;AACtB,sBAAc;AAAA,MAChB,OAAO;AACL,gBAAQ,KAAK,CAAC,aAAa,CAAC,CAAC;AAC7B,sBAAc;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AASA,SAAS,cAAc,UAAkB,aAA+C;AACtF,MAAI,OAAO;AACX,MAAI,QAAQ,YAAY,SAAS;AAEjC,SAAO,QAAQ,OAAO;AACpB,UAAM,MAAM,KAAK,OAAO,OAAO,SAAS,CAAC;AACzC,UAAM,CAAC,OAAO,GAAG,IAAI,YAAY,GAAG;AAEpC,QAAI,YAAY,SAAS,YAAY,KAAK;AACxC,aAAO;AAAA,IACT,WAAW,WAAW,OAAO;AAC3B,cAAQ,MAAM;AAAA,IAChB,OAAO;AACL,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAM,iBAAiB;AACvB,IAAM,0BAA0B;AAChC,IAAM,mBAAmB;AACzB,IAAM,wBAAwB;AAC9B,IAAM,oBAAoB;AAC1B,IAAM,gCAAgC;AACtC,IAAM,sBAAsB;AAW5B,SAAS,uBAAuB,MAAc,aAA8C;AAC1F,SAAO,KAAK;AAAA,IACV;AAAA,IACA,CAAC,OAAe,eAAmC,cAAkC,UAA0B;AAC7G,UAAI,cAAc,OAAO,WAAW,GAAG;AACrC,eAAO;AAAA,MACT;AACA,UAAI,kBAAkB,QAAW;AAC/B,eAAO,KAAK,aAAa;AAAA,MAC3B,WAAW,iBAAiB,QAAW;AACrC,eAAO,IAAI,YAAY;AAAA,MACzB;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAMA,IAAM,wBAAwB,CAAC;AAAA;AAAA,EAE7B,QAAQ,WAAW,uBAAuB,UAAU;AAAA;AAStD,SAAS,iBAAiB,MAAc,aAA8C;AAIpF,SAAO,KAAK,WAAW,mBAAmB,CAAC,OAAO,SAAS,QAAQ,UAAU;AAC3E,QAAI,cAAc,OAAO,WAAW,GAAG;AACrC,aAAO;AAAA,IACT;AACA,QAAI,YAAY,OAAW,QAAO,KAAK,sBAAsB,OAAO,CAAC;AACrE,QAAI,WAAW,OAAW,QAAO,IAAI,sBAAsB,MAAM,CAAC;AAClE,WAAO;AAAA,EACT,CAAC;AACH;AAWA,SAAS,sBAAsB,MAAc,aAA8C;AACzF,SAAO,KAAK,WAAW,+BAA+B,CAAC,OAAO,aAAqB,UAAkB;AACnG,QAAI,cAAc,OAAO,WAAW,GAAG;AACrC,aAAO;AAAA,IACT;AAIA,UAAM,qBAAqB,YAAY,WAAW,aAAa,KAAK;AACpE,WAAO,UAAU,kBAAkB;AAAA,EACrC,CAAC;AACH;AAEO,SAAS,gBAAgB,KAAqB;AAEnD,MAAI,CAAC,IAAI,SAAS,GAAG,KAAK,CAAC,IAAI,SAAS,KAAK,KAAK,CAAC,IAAI,SAAS,KAAK,EAAG,QAAO;AAE/E,MAAI,YAAY;AAGhB,cAAY,qBAAqB,SAAS;AAG1C,QAAM,cAAc,qBAAqB,SAAS;AAGlD,QAAM,QAAQ,CAAC;AACf,MAAI,YAAY;AAChB,QAAM,0BAA0B,UAAU,SAAS,cAAc;AACjE,QAAM,kBAAkB,MAAM,KAAK,uBAAuB;AAC1D,WAAS,IAAI,GAAG,IAAI,gBAAgB,QAAQ,KAAK;AAC/C,UAAM,QAAQ,gBAAgB,CAAC;AAC/B,UAAM,KAAK,UAAU,UAAU,WAAW,MAAM,KAAK,CAAC;AACtD,QAAI,aAAa;AACjB,QAAI,CAAC,cAAc,MAAM,OAAO,WAAW,GAAG;AAC5C,UAAI,2BAA2B;AAC/B,UAAI,IAAI,gBAAgB,SAAS,GAAG;AAClC,cAAM,YAAY,gBAAgB,IAAI,CAAC;AACvC,YAAI,UAAU,QAAQ,MAAM,QAAQ,GAAG;AACrC,qCAA2B,UAAU,UAAU,MAAM,QAAQ,GAAG,UAAU,KAAK;AAAA,QACjF;AAAA,MACF,OAAO;AACL,mCAA2B,UAAU,UAAU,MAAM,QAAQ,GAAG,UAAU,MAAM;AAAA,MAClF;AACA,YAAM,2BAA2B,yBAAyB,MAAM,aAAa,EAAE,CAAC;AAChF,UAAI,MAAM,KAAK,yBAAyB,SAAS,uBAAuB,CAAC,EAAE,SAAS,MAAM,GAAG;AAC3F,cAAM,oBAAoB,MAAM,KAAK,EAAE;AACvC,cAAM,0BAA0B,kBAAkB,MAAM,aAAa,EAAE,IAAI;AAC3E,cAAM,+CAA+C,0BAA0B;AAC/E,YACE,MAAM,KAAK,6CAA6C,SAAS,uBAAuB,CAAC,EAAE,SAAS,MACpG,GACA;AACA,uBAAa;AAAA,QACf;AAAA,MACF;AAAA,IACF,OAAO;AACL,mBAAa;AAAA,IACf;AACA,UAAM,KAAK,aAAa,QAAQ,GAAG;AACnC,gBAAY,MAAM,QAAQ;AAAA,EAC5B;AACA,QAAM,KAAK,UAAU,UAAU,SAAS,CAAC;AACzC,cAAY,MAAM,KAAK,EAAE;AACzB,UAAQ,IAAI,aAAa,SAAS;AAGlC,cAAY,uBAAuB,WAAW,WAAW;AAGzD,cAAY,iBAAiB,WAAW,WAAW;AAGnD,cAAY,sBAAsB,WAAW,WAAW;AAGxD,QAAM,SAAmB,CAAC;AAC1B,cAAY;AACZ,QAAM,8BAA8B,UAAU,SAAS,mBAAmB;AAC1E,aAAW,SAAS,6BAA6B;AAC/C,QAAI,CAAC,cAAc,MAAM,OAAO,WAAW,GAAG;AAC5C,aAAO,KAAK,UAAU,UAAU,WAAW,MAAM,KAAK,CAAC;AACvD,aAAO,KAAK,KAAK,MAAM,CAAC,CAAC,IAAI;AAC7B,kBAAY,MAAM,QAAQ,MAAM,CAAC,EAAE;AAAA,IACrC;AAAA,EACF;AACA,SAAO,KAAK,UAAU,UAAU,SAAS,CAAC;AAE1C,SAAO,OAAO,KAAK,EAAE;AACvB;;;AClPA,SAAS,mBAAmB,UAAkB,KAA6C;AACzF,SAAO,IAAI,OAAO,CAAC,QAAQ,OAAO,GAAG,MAAM,GAAG,KAAK;AACrD;AAEA,IAAM,4BAAuD,CAAC;AAE/C,SAAR,sBACL,SACA,qBAAgD,2BAChD;AACA,SAAO,mBAAmB,SAAS,iBAAiB,GAAG,kBAAkB;AAC3E;;;ACdA,IAAAC,gBAA8B;AAC9B,4BAA0C;AAC1C,0BAAwB;AACxB,wBAAsB;AACtB,kCAA+B;AAC/B,6BAA8C;AAC9C,2BAAyB;AACzB,iCAA8B;AAC9B,mDAA8C;AAC9C,0BAAwB;AACxB,wBAAsB;AACtB,yBAAuB;AACvB,oCAA0D;AAC1D,6BAA2B;AAC3B,mCAAkD;AAClD,uCAAoC;AACpC,gCAA8B;AAC9B,0BAAwB;AACxB,oCAAiC;AA2C7B,IAAAC,sBAAA;AAvCJ,IAAM,iCAAiC;AAAA,EACrC,wCAAuD,GAAG,8BAAAC;AAAA,EAC1D,gCAAmD,GAAG,0BAAAC;AAAA,EACtD,oBAA6C,GAAG,oBAAAC;AAClD;AAEA,IAAM,6BAA6B;AAAA,EACjC,4BAAsC,GAAG,6BAAAC;AAAA,EACzC,wCAA4C,GAAG;AAAA,EAC/C,4BAAsC,GAAG,uBAAAC;AAC3C;AAEA,IAAM,0BAAsC,CAAC;AAO7C,IAAM,wBAAoB,oBAAK,CAAC,EAAE,SAAS,iBAAiB,MAA8B;AACxF,QAAM,EAAE,OAAO,IAAI,yBAAyB;AAE5C,QAAM,EAAE,0BAA0B,qBAAqB,QAAI;AAAA,IACzD,OAAO;AAAA,MACL,0BAA0B,OAAO,qBAAqB,IAAI,CAAC,WAAW,2BAA2B,MAAM,CAAC;AAAA,MACxG,sBAAsB,OAAO,qBAAqB,gDAAoD;AAAA,IACxG;AAAA,IACA,CAAC,OAAO,oBAAoB;AAAA,EAC9B;AAEA,QAAM,mCAA+B,uBAAQ,MAAM;AACjD,WAAO,OAAO,yBAAyB,IAAI,CAAC,YAAY,+BAA+B,OAAO,CAAC;AAAA,EACjG,GAAG,CAAC,OAAO,wBAAwB,CAAC;AAEpC,QAAM,qBAAiB,uBAAQ,MAAM;AACnC,WAAO,mBAAmB,EAAE,GAAG,yBAAyB,GAAG,iBAAiB,IAAI;AAAA,EAClF,GAAG,CAAC,gBAAgB,CAAC;AAErB,SACE;AAAA,IAAC,sBAAAC;AAAA,IAAA;AAAA,MACC,eAAe;AAAA,QACb,kBAAAC;AAAA,QACA;AAAA,UACE,mBAAAC;AAAA,UACA;AAAA,YACE,sBAAsB;AAAA,UACxB;AAAA,QACF;AAAA,QACA,GAAG;AAAA,QACH,qBAAAC;AAAA,QACA,oBAAAC;AAAA,QACA,iCAAAC;AAAA,QACA,2BAAAC;AAAA,QACA,6CAAAC;AAAA,QACA,GAAG;AAAA,MACL;AAAA,MACA,eAAe;AAAA,QACb;AAAA,UACE,kBAAAC;AAAA,UACA;AAAA,YACE,aAAa,CAAC;AAAA,UAChB;AAAA,QACF;AAAA,QACA;AAAA,UACE,uBAAAC;AAAA,UACA;AAAA,YACE,GAAG;AAAA,YACH,UAAU,CAAC,GAAI,qCAAc,YAAY,CAAC,GAAI,MAAM;AAAA,YACpD,YAAY;AAAA,cACV,GAAG,qCAAc;AAAA;AAAA,cAEjB,MAAM,CAAC,CAAC,aAAa,eAAe,eAAe,cAAc,CAAC;AAAA,YACpE;AAAA,UACF;AAAA,QACF;AAAA,QACA,oBAAAC;AAAA,QACA,4BAAAC;AAAA,MACF;AAAA,MACA,qBAAqB;AAAA,QACnB,oBAAoB;AAAA,QACpB,UAAU;AAAA,UACR,GAAI,uBAAuB,oDAAsB,CAAC;AAAA,QACpD;AAAA,MACF;AAAA,MACA,YAAY;AAAA,MAIX;AAAA;AAAA,EACH;AAEJ,CAAC;AAED,kBAAkB,cAAc;AAEhC,IAAO,0BAAQ;;;ACrHf,IAAAC,gBAAkC;AAClC,qBAAoB;AAEL,SAAR,eAAmC,OAAa;AACrD,QAAM,UAAM,sBAAO,KAAK;AAGxB,QAAM,OAAO,IAAI;AACjB,QAAM,kBAAc,eAAAC,SAAQ,MAAM,KAAK,IAAI,OAAO;AAElD,+BAAU,MAAM;AACd,QAAI,UAAU;AAAA,EAChB,GAAG,CAAC,WAAW,CAAC;AAEhB,SAAO;AACT;;;ACfA,IAAAC,gBAAqB;AAInB,IAAAC,sBAAA;AADF,IAAM,wBAAoB,oBAAK,CAAC,EAAE,UAAU,UAAU,SAAS,YAAY,MACzE;AAAA,EAAC;AAAA;AAAA,IACC,WAAW,uBAAuB,WAAW,EAAE,IAAI,eAAe,EAAE,GAAG,KAAK;AAAA,IAC5E,OAAO,EAAE,OAAO,QAAQ,SAAS;AAAA,IAEhC;AAAA;AACH,CACD;AAED,kBAAkB,cAAc;AAEhC,IAAO,kBAAQ;;;APwDH,IAAAC,sBAAA;AArCZ,IAAM,sBAAsB,CAG1B;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY,aAAa;AAAA,EACzB,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,cAAc;AAChB,MAA6C;AAC3C,QAAM,eAAe,WAAY,OAAO,aAAa,WAAW,GAAG,QAAQ,OAAO,WAAY;AAE9F,QAAM,eAAe,eAAe,MAAM;AAC1C,QAAM,sBAAsB,eAAe,oBAAoB;AAC/D,QAAM,yBAAyB,eAAe,gBAAgB;AAE9D,QAAM,kBAAc;AAAA,IAClB,MAAO,UAAU,sBAAsB,SAAS,mBAAmB,IAAI;AAAA,IACvE,CAAC,SAAS,mBAAmB;AAAA,EAC/B;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,UAAU;AAAA,MACV,QAAQ;AAAA,MACR;AAAA,MAEA,uDAAC,cAAW,UAAU,cAAc,SAAkB,aACnD,uBACC,6CAAC,cACC,uDAAC,2BAAkB,SAAS,aAAa,kBAAkB,wBAAwB,GACrF,IAEA,6CAAC,2BAAkB,SAAS,aAAa,kBAAkB,wBAAwB,GAEvF;AAAA;AAAA,EACF;AAEJ;AAEA,IAAM,iBAAa,oBAAK,mBAAmB;AAC3C,WAAW,cAAc;AAEzB,IAAO,gBAAQ;","names":["import_react","AIMarkdownRenderExtraSyntax","AIMarkdownRenderDisplayOptimizeAbility","mergeWith","cloneDeep","import_react","import_jsx_runtime","remarkRemoveComments","remarkSmartypants","remarkPangu","remarkMarkHighlight","remarkSupersub","ReactMarkdown","remarkGfm","remarkMath","remarkBreaks","remarkEmoji","remarkSqueezeParagraphs","remarkCjkFriendly","remarkCjkFriendlyGfmStrikethrough","rehypeRaw","rehypeSanitize","rehypeKatex","rehypeUnwrapImages","import_react","isEqual","import_react","import_jsx_runtime","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.tsx","../src/context.tsx","../src/defs.ts","../src/preprocessors/latex.ts","../src/preprocessors/index.ts","../src/components/MarkdownContent.tsx","../src/hooks/useStableValue.ts","../src/components/typography/Default.tsx"],"sourcesContent":["/**\n * @ai-react-markdown/core\n *\n * A batteries-included React component for rendering AI-generated markdown\n * with first-class support for LaTeX math, GFM, CJK text, syntax highlighting,\n * and streaming content.\n *\n * ## Quick Start\n *\n * ```tsx\n * import AIMarkdown from '@ai-react-markdown/core';\n * import '@ai-react-markdown/core/typography/default.css';\n *\n * function App() {\n * return <AIMarkdown content=\"Hello **world**!\" />;\n * }\n * ```\n *\n * @module @ai-react-markdown/core\n */\n\n'use client';\n\nimport { useMemo, memo } from 'react';\nimport AIMarkdownRenderStateProvider, {\n AIMarkdownMetadataProvider,\n AIMarkdownRenderStateProviderProps,\n AIMarkdownMetadataProviderProps,\n} from './context';\nimport { AIMDContentPreprocessor } from './preprocessors/defs';\nimport preprocessAIMDContent from './preprocessors';\nimport AIMarkdownContent from './components/MarkdownContent';\nimport {\n AIMarkdownCustomComponents,\n AIMarkdownRenderConfig,\n AIMarkdownMetadata,\n AIMarkdownTypographyComponent,\n AIMarkdownExtraStylesComponent,\n AIMarkdownVariant,\n AIMarkdownColorScheme,\n} from './defs';\nimport useStableValue from './hooks/useStableValue';\nimport DefaultTypography from './components/typography/Default';\n\n/**\n * Props for the `<AIMarkdown>` component.\n *\n * @typeParam TConfig - Custom render configuration type (extends {@link AIMarkdownRenderConfig}).\n * @typeParam TRenderData - Custom metadata type (extends {@link AIMarkdownMetadata}).\n */\nexport interface AIMarkdownProps<\n TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig,\n TRenderData extends AIMarkdownMetadata = AIMarkdownMetadata,\n>\n extends\n Omit<AIMarkdownRenderStateProviderProps<TConfig>, 'fontSize' | 'variant' | 'colorScheme'>,\n AIMarkdownMetadataProviderProps<TRenderData> {\n /**\n * Base font size for the rendered output.\n * Accepts a CSS length string (e.g. `'14px'`, `'0.875rem'`) or a number\n * which is treated as pixels. Defaults to `'0.875rem'`.\n */\n fontSize?: number | string;\n /** Raw markdown content to render. */\n content: string;\n /**\n * Additional preprocessors to run on the raw markdown before rendering.\n * These run *after* the built-in LaTeX preprocessor.\n */\n contentPreprocessors?: AIMDContentPreprocessor[];\n /**\n * Custom `react-markdown` component overrides.\n * Use this to replace the default renderers for specific HTML elements\n * (e.g. code blocks, links, images).\n */\n customComponents?: AIMarkdownCustomComponents;\n /**\n * Typography wrapper component. Receives `fontSize`, `variant`, and `colorScheme`.\n * Defaults to the built-in {@link DefaultTypography}.\n */\n Typography?: AIMarkdownTypographyComponent;\n /**\n * Optional extra style wrapper component rendered between the typography\n * wrapper and the markdown content. Useful for injecting additional\n * CSS scope or theme providers.\n */\n ExtraStyles?: AIMarkdownExtraStylesComponent;\n /** Typography variant name. Defaults to `'default'`. */\n variant?: AIMarkdownVariant;\n /** Color scheme name. Defaults to `'light'`. */\n colorScheme?: AIMarkdownColorScheme;\n}\n\n/**\n * Root component that preprocesses markdown content and renders it through\n * a configurable remark/rehype pipeline wrapped in typography and style layers.\n */\nconst AIMarkdownComponent = <\n TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig,\n TRenderData extends AIMarkdownMetadata = AIMarkdownMetadata,\n>({\n streaming = false,\n content,\n fontSize,\n contentPreprocessors,\n customComponents,\n defaultConfig,\n config,\n metadata,\n Typography = DefaultTypography,\n ExtraStyles,\n variant = 'default',\n colorScheme = 'light',\n}: AIMarkdownProps<TConfig, TRenderData>) => {\n // Normalize fontSize: number -> px string, undefined -> default rem value.\n const usedFontSize = fontSize ? (typeof fontSize === 'number' ? `${fontSize}px` : fontSize) : '0.875rem';\n\n // Stabilize object/array props to prevent unnecessary re-renders\n // when the consumer creates new references on each render.\n const stableDefaultConfig = useStableValue(defaultConfig);\n const stableConfig = useStableValue(config);\n const stablePreprocessors = useStableValue(contentPreprocessors);\n const stableCustomComponents = useStableValue(customComponents);\n\n // Run the preprocessing pipeline (LaTeX normalization + user preprocessors).\n const usedContent = useMemo(\n () => (content ? preprocessAIMDContent(content, stablePreprocessors) : content),\n [content, stablePreprocessors]\n );\n\n return (\n <AIMarkdownMetadataProvider<TRenderData> metadata={metadata}>\n <AIMarkdownRenderStateProvider<TConfig>\n streaming={streaming}\n fontSize={usedFontSize}\n variant={variant}\n colorScheme={colorScheme}\n defaultConfig={stableDefaultConfig}\n config={stableConfig}\n >\n <Typography fontSize={usedFontSize} variant={variant} colorScheme={colorScheme}>\n {ExtraStyles ? (\n <ExtraStyles>\n <AIMarkdownContent content={usedContent} customComponents={stableCustomComponents} />\n </ExtraStyles>\n ) : (\n <AIMarkdownContent content={usedContent} customComponents={stableCustomComponents} />\n )}\n </Typography>\n </AIMarkdownRenderStateProvider>\n </AIMarkdownMetadataProvider>\n );\n};\n\n/**\n * A React component for rendering AI-generated markdown with rich formatting support.\n *\n * Features:\n * - GFM (tables, strikethrough, task lists, autolinks)\n * - LaTeX math rendering via KaTeX\n * - Emoji shortcodes\n * - CJK-friendly line breaking and spacing\n * - Configurable syntax extensions (highlight, definition lists, super/subscript)\n * - Configurable display optimizations (SmartyPants, pangu, comment removal)\n * - Streaming-aware rendering\n * - Customizable typography, color scheme, and component overrides\n *\n * @example\n * ```tsx\n * <AIMarkdown\n * content={markdownString}\n * streaming={isStreaming}\n * colorScheme=\"dark\"\n * config={{ extraSyntaxSupported: [AIMarkdownRenderExtraSyntax.HIGHLIGHT] }}\n * />\n * ```\n */\nconst AIMarkdown = memo(AIMarkdownComponent);\nAIMarkdown.displayName = 'AIMarkdown';\n\nexport default AIMarkdown as typeof AIMarkdownComponent;\n\n// ── Public API re-exports ───────────────────────────────────────────────────\n\n// Types\nexport type { AIMDContentPreprocessor };\nexport type {\n AIMarkdownCustomComponents,\n AIMarkdownRenderConfig,\n AIMarkdownRenderState,\n AIMarkdownMetadata,\n AIMarkdownTypographyProps,\n AIMarkdownTypographyComponent,\n AIMarkdownExtraStylesProps,\n AIMarkdownExtraStylesComponent,\n AIMarkdownVariant,\n AIMarkdownColorScheme,\n} from './defs';\n\n// Enums & Constants\nexport {\n AIMarkdownRenderExtraSyntax,\n AIMarkdownRenderDisplayOptimizeAbility,\n defaultAIMarkdownRenderConfig,\n} from './defs';\n\n// Hooks -- for custom components to access render state & metadata\nexport { useAIMarkdownRenderState, useAIMarkdownMetadata } from './context';\nexport { useStableValue };\n\n// Utils\nexport type { PartialDeep } from './typings/partial-deep';\n","/**\n * React context for the AIMarkdown render state.\n *\n * Provides an immutable {@link AIMarkdownRenderState} object to all descendant\n * components. The provider deep-merges user-supplied partial configuration with\n * the built-in defaults so that consumers always receive a complete config.\n *\n * @module context\n */\n\nimport { PropsWithChildren, createContext, useContext, useMemo } from 'react';\nimport cloneDeep from 'lodash-es/cloneDeep';\nimport mergeWith from 'lodash-es/mergeWith';\nimport {\n AIMarkdownRenderConfig,\n AIMarkdownMetadata,\n AIMarkdownRenderState,\n AIMarkdownVariant,\n AIMarkdownColorScheme,\n defaultAIMarkdownRenderConfig,\n} from './defs';\nimport type { PartialDeep } from './typings/partial-deep';\n\nconst AIMarkdownRenderStateContext = createContext<AIMarkdownRenderState<AIMarkdownRenderConfig> | null>(null);\n\nconst AIMarkdownMetadataContext = createContext<AIMarkdownMetadata | undefined>(undefined);\n\n/**\n * Access the current {@link AIMarkdownRenderState} from within the `<AIMarkdown>` tree.\n *\n * Must be called inside a component rendered as a descendant of `<AIMarkdown>`.\n * Throws if called outside the provider boundary.\n *\n * @typeParam TConfig - Expected configuration shape (defaults to {@link AIMarkdownRenderConfig}).\n * @returns The current render state (does not include metadata — use {@link useAIMarkdownMetadata} for that).\n *\n * @example\n * ```tsx\n * function CustomCodeBlock({ children }: PropsWithChildren) {\n * const { streaming, config } = useAIMarkdownRenderState();\n * // ...\n * }\n * ```\n */\nexport function useAIMarkdownRenderState<TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig>() {\n const context = useContext(AIMarkdownRenderStateContext) as AIMarkdownRenderState<TConfig>;\n\n if (!context) {\n throw new Error('useAIMarkdownRenderState must be used within an <AIMarkdown /> component.');\n }\n\n return context;\n}\n\n/**\n * Access the current metadata from within the `<AIMarkdown>` tree.\n *\n * Metadata lives in a separate React context so that changes to metadata\n * do not cause re-renders in components that only consume render state\n * (e.g. {@link MarkdownContent}).\n *\n * @typeParam TMetadata - Expected metadata shape (defaults to {@link AIMarkdownMetadata}).\n * @returns The current metadata, or `undefined` if none was provided.\n */\nexport function useAIMarkdownMetadata<TMetadata extends AIMarkdownMetadata = AIMarkdownMetadata>() {\n return useContext(AIMarkdownMetadataContext) as TMetadata | undefined;\n}\n\n/** Props for {@link AIMarkdownRenderStateProvider}. */\nexport interface AIMarkdownRenderStateProviderProps<\n TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig,\n> extends PropsWithChildren {\n streaming: boolean;\n fontSize: string;\n variant: AIMarkdownVariant;\n colorScheme: AIMarkdownColorScheme;\n /**\n * Base default config to merge against. When omitted, falls back to\n * {@link defaultAIMarkdownRenderConfig}. Sub-packages (e.g. mantine) can\n * pass their own extended defaults here.\n */\n defaultConfig?: TConfig;\n /** Partial config that will be deep-merged with the default config. */\n config?: PartialDeep<TConfig>;\n}\n\n/** Props for {@link AIMarkdownMetadataProvider}. */\nexport interface AIMarkdownMetadataProviderProps<\n TMetadata extends AIMarkdownMetadata = AIMarkdownMetadata,\n> extends PropsWithChildren {\n metadata?: TMetadata;\n}\n\n/**\n * Custom lodash `mergeWith` handler: arrays from the source (user config)\n * fully replace the target (default config) instead of being merged by index.\n */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nconst configMergeCustomizer = (\n _objValue: any,\n srcValue: any,\n _key: string,\n _object: any,\n _source: any,\n _stack: any\n) => {\n if (Array.isArray(srcValue)) {\n return srcValue;\n }\n};\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\n/**\n * Provider that exposes consumer-provided metadata via a dedicated React context.\n * Separated from render state so that metadata changes do not trigger\n * re-renders in components that only consume render state.\n */\nexport const AIMarkdownMetadataProvider = <RDT extends AIMarkdownMetadata = AIMarkdownMetadata>({\n metadata,\n children,\n}: AIMarkdownMetadataProviderProps<RDT>) => {\n return <AIMarkdownMetadataContext.Provider value={metadata}>{children}</AIMarkdownMetadataContext.Provider>;\n};\n\n/**\n * Internal provider that deep-merges user config with defaults and exposes\n * the resulting {@link AIMarkdownRenderState} to the component tree.\n */\nconst AIMarkdownRenderStateProvider = <RCT extends AIMarkdownRenderConfig = AIMarkdownRenderConfig>({\n streaming,\n fontSize,\n variant,\n colorScheme,\n defaultConfig,\n config,\n children,\n}: AIMarkdownRenderStateProviderProps<RCT>) => {\n // Deep-merge user config with defaults; clone first to avoid mutating the frozen default.\n const baseConfig = defaultConfig ?? defaultAIMarkdownRenderConfig;\n const mergedConfig = useMemo(\n () => (config ? mergeWith(cloneDeep(baseConfig), config, configMergeCustomizer) : baseConfig),\n [baseConfig, config]\n );\n\n // Freeze the state object to enforce immutability downstream.\n const state = useMemo(\n () =>\n Object.freeze({\n streaming,\n fontSize,\n variant,\n colorScheme,\n config: mergedConfig,\n }),\n [streaming, fontSize, variant, colorScheme, mergedConfig]\n );\n\n return <AIMarkdownRenderStateContext.Provider value={state}>{children}</AIMarkdownRenderStateContext.Provider>;\n};\n\nexport default AIMarkdownRenderStateProvider;\n","/**\n * Core type definitions, enums, and default configuration for ai-react-markdown.\n *\n * This module defines the public API surface for configuring the renderer,\n * including extra markdown syntax extensions, display optimization abilities,\n * typography theming, and the shared render state shape.\n *\n * @module defs\n */\n\nimport { ComponentType, PropsWithChildren } from 'react';\nimport type { Components } from 'react-markdown';\n\n/**\n * Custom component overrides for the markdown renderer.\n * Alias for `react-markdown`'s `Components` type, re-exported under the\n * library's `AIMarkdown` naming convention so consumers don't need a\n * direct `react-markdown` dependency for type imports.\n */\nexport type AIMarkdownCustomComponents = Components;\n\n/**\n * Extra markdown syntax extensions beyond standard GFM.\n * Enable or disable these via {@link AIMarkdownRenderConfig.extraSyntaxSupported}.\n */\nexport enum AIMarkdownRenderExtraSyntax {\n /** `==Highlight==` syntax support. */\n HIGHLIGHT = 'HIGHLIGHT',\n /** Definition list syntax. @see https://michelf.ca/projects/php-markdown/extra/#def-list */\n DEFINITION_LIST = 'DEFINITION_LIST',\n /** Superscript (`^text^`) and subscript (`~text~`) syntax. */\n SUBSCRIPT = 'SUBSCRIPT',\n}\n\n/**\n * Display optimization abilities applied during markdown processing.\n * Enable or disable these via {@link AIMarkdownRenderConfig.displayOptimizeAbilities}.\n */\nexport enum AIMarkdownRenderDisplayOptimizeAbility {\n /** Strip HTML comments from the content. */\n REMOVE_COMMENTS = 'REMOVE_COMMENTS',\n /** Typographic enhancements via SmartyPants (curly quotes, em-dashes, etc.). @see https://www.npmjs.com/package/smartypants */\n SMARTYPANTS = 'SMARTYPANTS',\n /** Automatically insert spaces between CJK and half-width characters. */\n PANGU = 'PANGU',\n}\n\n/**\n * Configuration object controlling which markdown extensions and\n * display optimizations are active during rendering.\n */\nexport interface AIMarkdownRenderConfig {\n /** Extra syntax extensions to enable. */\n extraSyntaxSupported: AIMarkdownRenderExtraSyntax[];\n /** Display optimization abilities to enable. */\n displayOptimizeAbilities: AIMarkdownRenderDisplayOptimizeAbility[];\n}\n\n/**\n * Sensible default configuration with all extensions and optimizations enabled.\n * Frozen to prevent accidental mutation.\n */\nexport const defaultAIMarkdownRenderConfig: AIMarkdownRenderConfig = Object.freeze({\n extraSyntaxSupported: Object.freeze([\n AIMarkdownRenderExtraSyntax.HIGHLIGHT,\n AIMarkdownRenderExtraSyntax.DEFINITION_LIST,\n AIMarkdownRenderExtraSyntax.SUBSCRIPT,\n ]),\n displayOptimizeAbilities: Object.freeze([\n AIMarkdownRenderDisplayOptimizeAbility.REMOVE_COMMENTS,\n AIMarkdownRenderDisplayOptimizeAbility.SMARTYPANTS,\n AIMarkdownRenderDisplayOptimizeAbility.PANGU,\n ]),\n}) as AIMarkdownRenderConfig;\n\n/**\n * Arbitrary metadata that consumers can pass through a dedicated React context.\n * Custom renderers can access this via the {@link useAIMarkdownMetadata} hook.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface AIMarkdownMetadata extends Record<string, any> {}\n\n/**\n * Typography variant identifier. Built-in variant is `'default'`;\n * consumers may define additional variants via custom typography components.\n */\nexport type AIMarkdownVariant = 'default' | (string & {});\n\n/**\n * Color scheme identifier. Built-in schemes are `'light'` and `'dark'`;\n * consumers may define additional schemes via custom typography CSS.\n */\nexport type AIMarkdownColorScheme = 'light' | 'dark' | (string & {});\n\n/** Props accepted by a typography wrapper component. */\nexport interface AIMarkdownTypographyProps extends PropsWithChildren {\n /** Resolved CSS font-size value (e.g. `'14px'`, `'0.875rem'`). */\n fontSize: string;\n /** Active typography variant. */\n variant?: AIMarkdownVariant;\n /** Active color scheme. */\n colorScheme?: AIMarkdownColorScheme;\n}\n\n/** React component type for the typography wrapper. */\nexport type AIMarkdownTypographyComponent = ComponentType<AIMarkdownTypographyProps>;\n\n/** Props accepted by an optional extra style wrapper component. */\nexport interface AIMarkdownExtraStylesProps extends PropsWithChildren {}\n\n/** React component type for an optional extra style wrapper. */\nexport type AIMarkdownExtraStylesComponent = ComponentType<AIMarkdownExtraStylesProps>;\n\n/**\n * Immutable render state exposed to all descendant components via React context.\n * Access this with the {@link useAIMarkdownRenderState} hook.\n *\n * Metadata is provided via a separate context — use {@link useAIMarkdownMetadata} instead.\n *\n * @typeParam TConfig - Render configuration type (defaults to {@link AIMarkdownRenderConfig}).\n */\nexport interface AIMarkdownRenderState<TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig> {\n /** Whether the content is currently being streamed (e.g. from an LLM). */\n streaming: boolean;\n /** Resolved CSS font-size value. */\n fontSize: string;\n /** Active typography variant. */\n variant: AIMarkdownVariant;\n /** Active color scheme. */\n colorScheme: AIMarkdownColorScheme;\n /** Active render configuration. */\n config: TConfig;\n}\n","/**\n * LaTeX preprocessing pipeline.\n *\n * Normalizes raw markdown so that LaTeX expressions survive the remark/rehype\n * rendering pipeline intact. The main entry point is {@link preprocessLaTeX},\n * which splits content into protected regions (code blocks, inline code, HTML\n * tags) and applies a sequence of transformations to the unprotected text:\n *\n * 1. Escape mhchem commands (`\\ce`, `\\pu`)\n * 2. Escape currency dollar signs (e.g. `$100`, `$1,000.50`)\n * 3. Convert bracket delimiters (`\\[...\\]`, `\\(...\\)`) to dollar delimiters\n * 4. Escape pipes inside LaTeX to prevent GFM table interference\n * 5. Escape underscores inside `\\text{...}` commands\n * 6. Convert single-dollar delimiters to double-dollar delimiters\n *\n * Thanks to the implementations from the following repositories:\n * - https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n * - https://github.com/danny-avila/LibreChat/blob/main/client/src/utils/latex.ts\n *\n * @module preprocessors/latex\n */\n\ninterface Segment {\n text: string;\n isCode: boolean;\n}\n\n/**\n * Split content into alternating text and protected segments.\n * Protected segments (isCode: true) are excluded from LaTeX processing:\n * - ``` multiline code blocks\n * - ` inline code\n * - HTML tags (e.g. <span>$</span> where $ should not be treated as LaTeX)\n */\nfunction splitByProtectedRegions(content: string): Segment[] {\n const segments: Segment[] = [];\n let lastIndex = 0;\n let inlineStart = -1;\n let multilineStart = -1;\n\n function pushProtected(start: number, end: number) {\n if (start > lastIndex) {\n segments.push({ text: content.substring(lastIndex, start), isCode: false });\n }\n segments.push({ text: content.substring(start, end), isCode: true });\n lastIndex = end;\n }\n\n for (let i = 0; i < content.length; i++) {\n const char = content[i];\n\n // Check for multiline code blocks\n if (char === '`' && i + 2 < content.length && content[i + 1] === '`' && content[i + 2] === '`') {\n if (multilineStart === -1) {\n // Cancel any pending inline code — ``` takes priority over `\n inlineStart = -1;\n multilineStart = i;\n i += 2;\n } else {\n pushProtected(multilineStart, i + 3);\n multilineStart = -1;\n i += 2;\n }\n }\n // Check for inline code (only if not in multiline)\n else if (char === '`' && multilineStart === -1) {\n if (inlineStart === -1) {\n inlineStart = i;\n } else {\n pushProtected(inlineStart, i + 1);\n inlineStart = -1;\n }\n }\n // Check for HTML tags (only if not in code block)\n else if (char === '<' && multilineStart === -1 && inlineStart === -1) {\n // Only match known HTML tags to avoid false positives with angle brackets\n // in markdown links (<Slides Demo>), math comparisons ($a < b$), etc.\n const rest = content.substring(i);\n const tagMatch = rest.match(\n /^<\\/?(span|div|p|br|hr|img|a|em|strong|b|i|u|s|sub|sup|code|pre|table|tr|td|th|thead|tbody|tfoot|ul|ol|li|dl|dt|dd|h[1-6]|blockquote|details|summary|figure|figcaption|section|article|aside|nav|header|footer|main|mark|del|ins|small|abbr|cite|dfn|kbd|samp|var|ruby|rt|rp|bdo|wbr|input|button|select|textarea|label|fieldset|legend|output|iframe|video|audio|source|canvas|svg|math|time)(?:\\s[^>]*)?\\/?>/i\n );\n if (tagMatch) {\n pushProtected(i, i + tagMatch[0].length);\n i += tagMatch[0].length - 1; // -1 because loop does i++\n }\n }\n }\n\n // Push remaining text\n if (lastIndex < content.length) {\n segments.push({ text: content.substring(lastIndex), isCode: false });\n }\n\n return segments;\n}\n\n/**\n * Escape mhchem commands in LaTeX expressions to ensure proper rendering.\n *\n * @param text Input string containing LaTeX expressions with mhchem commands\n * @returns String with escaped mhchem commands\n * @from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction escapeMhchemCommands(text: string) {\n return text.replaceAll('$\\\\ce{', '$\\\\\\\\ce{').replaceAll('$\\\\pu{', '$\\\\\\\\pu{');\n}\n\nconst CURRENCY_REGEX = /(?<![\\\\$])\\$(?!\\$)(?=\\d+(?:,\\d{3})*(?:\\.\\d+)?(?:[KMBkmb])?(?:\\s|$|[^a-zA-Z\\d]))/g;\nconst NO_ESCAPED_DOLLAR_REGEX = /(?<![\\\\$])\\$(?!\\$)/g;\n// Match \\[...\\] and \\(...\\) as LaTeX delimiters, but exclude:\n// - !\\[...\\] (markdown image)\n// - \\[...\\]( (markdown link)\nconst DELIMITERS_REGEX = /(?<!!)\\\\\\[([\\S\\s]*?[^\\\\])\\\\](?!\\()|\\\\\\((.*?)\\\\\\)/g;\nconst ARRAY_COL_SPEC_OR_PIPE_REGEX = /(\\\\begin\\{(?:array|tabular[x*]?)\\}\\{[^}]*\\})|(?<!\\\\)\\|/g;\n// Display $$ allows multiline; inline $ forbids newlines (consistent with SINGLE_DOLLAR_REGEX)\nconst LATEX_BLOCK_REGEX = /\\$\\$([\\S\\s]*?)\\$\\$|(?<![\\\\$])\\$(?!\\$)((?:[^$\\n]|\\\\\\$)*?)(?<![\\\\`])\\$(?!\\$)/g;\nconst ESCAPE_TEXT_UNDERSCORES_REGEX = /\\\\text{([^}]*)}/g;\nconst SINGLE_DOLLAR_REGEX = /(?<![\\\\$])\\$(?!\\$)((?:[^$\\n]|\\\\[$])+?)(?<!\\\\)(?<!`)\\$(?!\\$)/g;\n\n/**\n * Escape currency dollar signs (e.g. $100, $1,000.50) so they are not\n * misinterpreted as LaTeX delimiters.\n *\n * The tricky part: a `$` followed by digits might still be inside a LaTeX\n * expression (e.g. `$8.29 \\text{ B} \\times 4$`). We detect this by checking\n * whether there is an odd number of unescaped `$` on the same line after the\n * current match — if so, the current `$` is a LaTeX opener, not currency.\n */\nfunction escapeCurrencyDollarSigns(text: string): string {\n const parts: string[] = [];\n let lastIndex = 0;\n const currencyMatches = Array.from(text.matchAll(CURRENCY_REGEX));\n\n for (let i = 0; i < currencyMatches.length; i++) {\n const match = currencyMatches[i];\n parts.push(text.substring(lastIndex, match.index));\n\n let needEscape = true;\n let restBeforeNextMatchOrEnd = '';\n if (i < currencyMatches.length - 1) {\n const nextMatch = currencyMatches[i + 1];\n if (nextMatch.index - match.index > 1) {\n restBeforeNextMatchOrEnd = text.substring(match.index + 1, nextMatch.index);\n }\n } else {\n restBeforeNextMatchOrEnd = text.substring(match.index + 1);\n }\n const firstLineBeforeNextMatch = restBeforeNextMatchOrEnd.split(/\\r\\n|\\r|\\n/g)[0];\n if (Array.from(firstLineBeforeNextMatch.matchAll(NO_ESCAPED_DOLLAR_REGEX)).length % 2 !== 0) {\n const previousNewContent = parts.join('');\n const previousLastLineContent = previousNewContent.split(/\\r\\n|\\r|\\n/g).pop();\n const wholeLineBeforeNextMatchWithoutCurrentDollar = previousLastLineContent + firstLineBeforeNextMatch;\n if (Array.from(wholeLineBeforeNextMatchWithoutCurrentDollar.matchAll(NO_ESCAPED_DOLLAR_REGEX)).length % 2 !== 0) {\n needEscape = false;\n }\n }\n\n parts.push(needEscape ? '\\\\$' : '$');\n lastIndex = match.index + 1;\n }\n parts.push(text.substring(lastIndex));\n return parts.join('');\n}\n\n/**\n * Convert LaTeX bracket delimiters to dollar sign delimiters.\n * Converts \\[...\\] to $$...$$ and \\(...\\) to $...$\n *\n * @param text Input string containing LaTeX expressions\n * @returns String with LaTeX bracket delimiters converted to dollar sign delimiters\n * @modified from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction convertLatexDelimiters(text: string): string {\n return text.replaceAll(\n DELIMITERS_REGEX,\n (match: string, squareBracket: string | undefined, roundBracket: string | undefined): string => {\n if (squareBracket !== undefined) {\n return `$$${squareBracket}$$`;\n } else if (roundBracket !== undefined) {\n return `$${roundBracket}$`;\n }\n return match;\n }\n );\n}\n\n/**\n * Helper function: replace unescaped pipes with \\vert in LaTeX math fragments\n * @from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nconst replaceUnescapedPipes = (formula: string): string =>\n // Use \\vert{} so the control sequence terminates before the next token.\n // Preserve `|` inside \\begin{array}{...} / \\begin{tabular}{...} column specifiers.\n formula.replaceAll(ARRAY_COL_SPEC_OR_PIPE_REGEX, (match, colSpec: string | undefined) =>\n colSpec !== undefined ? match : '\\\\vert{}'\n );\n/**\n * Escape pipes in LaTeX expressions to prevent them from being interpreted as\n * column separators in markdown tables.\n *\n * @param text Input string containing LaTeX expressions\n * @returns String with pipes escaped in LaTeX expressions\n * @modified from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction escapeLatexPipes(text: string): string {\n return text.replaceAll(LATEX_BLOCK_REGEX, (match, display, inline) => {\n if (display !== undefined) return `$$${replaceUnescapedPipes(display)}$$`;\n if (inline !== undefined) return `$${replaceUnescapedPipes(inline)}$`;\n return match;\n });\n}\n\n/**\n * Escape unescaped underscores within \\text{...} commands in LaTeX expressions.\n * For example, \\text{node_domain} becomes \\text{node\\_domain},\n * but \\text{node\\_domain} remains \\text{node\\_domain}.\n *\n * @param text Input string that may contain LaTeX expressions\n * @returns String with unescaped underscores escaped within \\text{...} commands\n * @modified from https://github.com/lobehub/lobe-ui/blob/master/src/hooks/useMarkdown/latex.ts\n */\nfunction escapeTextUnderscores(text: string): string {\n return text.replaceAll(ESCAPE_TEXT_UNDERSCORES_REGEX, (_match, textContent: string) => {\n const escapedTextContent = textContent.replaceAll(/(?<!\\\\)_/g, '\\\\_');\n return `\\\\text{${escapedTextContent}}`;\n });\n}\n\n/**\n * Convert single dollar delimiters to double dollar delimiters.\n * e.g. $x^2$ → $$x^2$$\n */\nfunction convertSingleToDoubleDollar(text: string): string {\n return text.replaceAll(SINGLE_DOLLAR_REGEX, (_match, content: string) => `$$${content}$$`);\n}\n\n/**\n * Main LaTeX preprocessor entry point.\n *\n * Splits the input into protected regions (code blocks, inline code, HTML tags)\n * and applies the full normalization pipeline to unprotected text segments.\n * Returns the input unchanged when no LaTeX-related characters (`$`, `\\[`, `\\(`)\n * are detected.\n *\n * @param str - Raw markdown string.\n * @returns The preprocessed string with normalized LaTeX delimiters.\n */\nexport function preprocessLaTeX(str: string): string {\n // Return early if no LaTeX patterns are found\n if (!str.includes('$') && !str.includes('\\\\[') && !str.includes('\\\\(')) return str;\n\n // Step 1: split by code blocks\n const segments = splitByProtectedRegions(str);\n\n // Step 2: process each non-code segment through the LaTeX pipeline\n const result = segments.map((segment) => {\n if (segment.isCode) return segment.text;\n\n let text = segment.text;\n text = escapeMhchemCommands(text);\n text = escapeCurrencyDollarSigns(text);\n text = convertLatexDelimiters(text);\n text = escapeLatexPipes(text);\n text = escapeTextUnderscores(text);\n text = convertSingleToDoubleDollar(text);\n return text;\n });\n\n return result.join('');\n}\n","/**\n * Content preprocessing pipeline.\n *\n * Runs all preprocessors (built-in + user-supplied) in sequence before\n * the markdown string is handed to react-markdown. The built-in LaTeX\n * preprocessor always runs first, followed by any extra preprocessors\n * provided by the consumer.\n *\n * @module preprocessors\n */\n\nimport { AIMDContentPreprocessor } from './defs';\nimport { preprocessLaTeX } from './latex';\n\n/** Sequentially apply an array of preprocessor functions via left-fold. */\nfunction applyPreprocessors(value: string, ...fns: Array<AIMDContentPreprocessor>): string {\n return fns.reduce((result, fn) => fn(result), value);\n}\n\n/** Stable empty array to avoid re-renders when no extra preprocessors are given. */\nconst defaultExtraPreprocessors: AIMDContentPreprocessor[] = [];\n\n/**\n * Run the full preprocessing pipeline on raw markdown content.\n *\n * @param content - Raw markdown string.\n * @param extraPreprocessors - Optional user-supplied preprocessors appended after the built-in ones.\n * @returns The preprocessed markdown string ready for rendering.\n */\nexport default function preprocessAIMDContent(\n content: string,\n extraPreprocessors: AIMDContentPreprocessor[] = defaultExtraPreprocessors\n) {\n return applyPreprocessors(content, preprocessLaTeX, ...extraPreprocessors);\n}\n","/**\n * Core markdown rendering component.\n *\n * Wraps `react-markdown` with a curated set of remark and rehype plugins\n * for GFM, math/LaTeX, emoji, CJK support, and configurable extra syntax\n * extensions and display optimizations. Plugin selection is driven by the\n * {@link AIMarkdownRenderConfig} from context.\n *\n * @module components/MarkdownContent\n */\n\nimport { memo, useMemo } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport rehypeKatex from 'rehype-katex';\nimport rehypeRaw from 'rehype-raw';\nimport rehypeUnwrapImages from 'rehype-unwrap-images';\nimport rehypeSanitize, { defaultSchema } from 'rehype-sanitize';\nimport remarkBreaks from 'remark-breaks';\nimport remarkCjkFriendly from 'remark-cjk-friendly';\nimport remarkCjkFriendlyGfmStrikethrough from 'remark-cjk-friendly-gfm-strikethrough';\nimport remarkEmoji from 'remark-emoji';\nimport remarkGfm from 'remark-gfm';\nimport remarkMath from 'remark-math';\nimport { remarkDefinitionList, defListHastHandlers } from 'remark-definition-list';\nimport remarkSupersub from 'remark-supersub';\nimport { remarkMark as remarkMarkHighlight } from 'remark-mark-highlight';\nimport remarkSqueezeParagraphs from 'remark-squeeze-paragraphs';\nimport remarkSmartypants from 'remark-smartypants';\nimport remarkPangu from 'remark-pangu';\nimport remarkRemoveComments from 'remark-remove-comments';\nimport { useAIMarkdownRenderState } from '../context';\nimport {\n AIMarkdownCustomComponents,\n AIMarkdownRenderDisplayOptimizeAbility,\n AIMarkdownRenderExtraSyntax,\n} from '../defs';\n\n/** Maps display optimization abilities to their corresponding remark plugins. */\nconst DisplayOptimizeRemarkPluginMap = {\n [AIMarkdownRenderDisplayOptimizeAbility.REMOVE_COMMENTS]: remarkRemoveComments,\n [AIMarkdownRenderDisplayOptimizeAbility.SMARTYPANTS]: remarkSmartypants,\n [AIMarkdownRenderDisplayOptimizeAbility.PANGU]: remarkPangu,\n};\n\n/** Maps extra syntax extensions to their corresponding remark plugins. */\nconst ExtraSyntaxRemarkPluginMap = {\n [AIMarkdownRenderExtraSyntax.HIGHLIGHT]: remarkMarkHighlight,\n [AIMarkdownRenderExtraSyntax.DEFINITION_LIST]: remarkDefinitionList,\n [AIMarkdownRenderExtraSyntax.SUBSCRIPT]: remarkSupersub,\n};\n\n/** Stable empty object to avoid unnecessary re-renders when no custom components are given. */\nconst DefaultCustomComponents: AIMarkdownCustomComponents = {};\n\ninterface AIMarkdownContentProps {\n /** Preprocessed markdown string to render. */\n content: string;\n /** Optional react-markdown component overrides (e.g. custom code block renderer). */\n customComponents?: AIMarkdownCustomComponents;\n}\n\n/**\n * Internal component that assembles the remark/rehype plugin chain based on\n * the current render config and delegates to `ReactMarkdown`.\n */\nconst AIMarkdownContent = memo(({ content, customComponents }: AIMarkdownContentProps) => {\n const { config } = useAIMarkdownRenderState();\n\n // Resolve extra-syntax remark plugins and check if definition list HAST handlers are needed.\n const { extraSyntaxRemarkPlugins, enableDefinitionList } = useMemo(\n () => ({\n extraSyntaxRemarkPlugins: config.extraSyntaxSupported.map((syntax) => ExtraSyntaxRemarkPluginMap[syntax]),\n enableDefinitionList: config.extraSyntaxSupported.includes(AIMarkdownRenderExtraSyntax.DEFINITION_LIST),\n }),\n [config.extraSyntaxSupported]\n );\n\n const displayOptimizeRemarkPlugins = useMemo(() => {\n return config.displayOptimizeAbilities.map((ability) => DisplayOptimizeRemarkPluginMap[ability]);\n }, [config.displayOptimizeAbilities]);\n\n const usedComponents = useMemo(() => {\n return customComponents ? { ...DefaultCustomComponents, ...customComponents } : DefaultCustomComponents;\n }, [customComponents]);\n\n return (\n <ReactMarkdown\n remarkPlugins={[\n // --- Core plugins (always active) ---\n remarkGfm,\n [\n remarkMath,\n {\n // Disable single-dollar inline math to avoid conflicts with currency\n // signs and other dollar usages; the preprocessor converts $...$ to $$...$$.\n singleDollarTextMath: false,\n },\n ],\n // --- Configurable extra syntax plugins ---\n ...extraSyntaxRemarkPlugins,\n // --- Formatting & normalization ---\n remarkBreaks,\n remarkEmoji,\n remarkSqueezeParagraphs,\n remarkCjkFriendly,\n remarkCjkFriendlyGfmStrikethrough,\n // --- Configurable display optimizations ---\n ...displayOptimizeRemarkPlugins,\n ]}\n rehypePlugins={[\n // Allow raw HTML through so rehype-sanitize can handle it.\n [\n rehypeRaw,\n {\n passThrough: [],\n },\n ],\n // Sanitize HTML while allowing <mark> (highlight) and KaTeX class names.\n [\n rehypeSanitize,\n {\n ...defaultSchema,\n tagNames: [...(defaultSchema.tagNames || []), 'mark'],\n attributes: {\n ...defaultSchema.attributes,\n // The `language-*` regex is allowed by default.\n code: [['className', /^language-./, 'math-inline', 'math-display']],\n },\n },\n ],\n rehypeKatex,\n rehypeUnwrapImages,\n ]}\n remarkRehypeOptions={{\n allowDangerousHtml: true,\n handlers: {\n // Inject definition-list HAST handlers when the extension is active.\n ...(enableDefinitionList ? defListHastHandlers : {}),\n },\n }}\n components={usedComponents}\n // NOTE: The default `urlTransform` in Windows environments treats local\n // paths (e.g. `C:/...`) as unsafe. Uncomment the line below if needed:\n // urlTransform={(url: string) => url}\n >\n {content}\n </ReactMarkdown>\n );\n});\n\nAIMarkdownContent.displayName = 'AIMarkdownContent';\n\nexport default AIMarkdownContent;\n","/**\n * Hook for referential stability of deep-equal values.\n *\n * @module hooks/useStableValue\n */\n\nimport { useRef, useEffect } from 'react';\nimport isEqual from 'lodash-es/isEqual';\n\n/**\n * Returns a referentially stable version of `value`.\n *\n * On each render the new value is deep-compared (via `lodash/isEqual`) against\n * the previous one. If they are structurally equal the *previous* reference is\n * returned, preventing unnecessary re-renders in downstream `useMemo` / `useEffect`\n * consumers that depend on reference equality.\n *\n * @typeParam T - The value type.\n * @param value - The potentially new value to stabilize.\n * @returns The previous reference when deep-equal, otherwise the new value.\n *\n * @example\n * ```tsx\n * const stableConfig = useStableValue(config);\n * // stableConfig keeps the same reference as long as config is deep-equal.\n * ```\n */\nexport default function useStableValue<T>(value: T): T {\n const ref = useRef(value);\n\n // eslint-disable-next-line react-hooks/refs\n const prev = ref.current;\n const stableValue = isEqual(prev, value) ? prev : value;\n\n useEffect(() => {\n ref.current = stableValue;\n }, [stableValue]);\n\n return stableValue;\n}\n","/**\n * Default typography wrapper component.\n *\n * Renders a `<div>` container that applies CSS class names for the active\n * variant and color scheme, and sets the root font-size as an inline style.\n * The corresponding CSS custom properties are defined in the SCSS variant\n * files under `typography/variants/`.\n *\n * Consumers can replace this with a custom {@link AIMarkdownTypographyComponent}\n * via the `Typography` prop on `<AIMarkdown>`.\n *\n * @module components/typography/Default\n */\n\nimport { memo } from 'react';\nimport type { AIMarkdownTypographyProps } from '../../defs';\n\nconst DefaultTypography = memo(({ children, fontSize, variant, colorScheme }: AIMarkdownTypographyProps) => (\n <div\n className={`aim-typography-root ${variant ?? ''} ${colorScheme ?? ''}`.trim()}\n style={{ width: '100%', fontSize }}\n >\n {children}\n </div>\n));\n\nDefaultTypography.displayName = 'DefaultTypography';\n\nexport default DefaultTypography;\n"],"mappings":"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","names":["import_react","AIMarkdownRenderExtraSyntax","AIMarkdownRenderDisplayOptimizeAbility","mergeWith","cloneDeep","import_react","import_jsx_runtime","remarkRemoveComments","remarkSmartypants","remarkPangu","remarkMarkHighlight","remarkSupersub","ReactMarkdown","remarkGfm","remarkMath","remarkBreaks","remarkEmoji","remarkSqueezeParagraphs","remarkCjkFriendly","remarkCjkFriendlyGfmStrikethrough","rehypeRaw","rehypeSanitize","rehypeKatex","rehypeUnwrapImages","import_react","isEqual","import_react","import_jsx_runtime","import_jsx_runtime"]}