From d94fde3464375ebd3fed93f6a5f59a2923e93cfc Mon Sep 17 00:00:00 2001 From: chenman Date: Wed, 3 Jun 2026 11:19:06 +0800 Subject: [PATCH] refactor(react): use declarative HTML for known Text variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Known variants (h1–h5, caption) now render using native HTML elements directly instead of prepending Markdown syntax and relying on the Markdown renderer. This aligns the React renderer with the Angular fix in #1502. Markdown rendering is still used for unknown/default variants (e.g. 'body') to preserve rich text support. Fixes: #1516 --- .../v0_9/catalog/basic/components/Text.tsx | 58 ++++++++----------- .../tests/v0_9/catalog-components.test.tsx | 2 +- .../tests/v0_9/integration-scenarios.test.tsx | 6 +- 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/renderers/react/src/v0_9/catalog/basic/components/Text.tsx b/renderers/react/src/v0_9/catalog/basic/components/Text.tsx index 508c24687..18dd39d87 100644 --- a/renderers/react/src/v0_9/catalog/basic/components/Text.tsx +++ b/renderers/react/src/v0_9/catalog/basic/components/Text.tsx @@ -22,54 +22,46 @@ import {useMarkdown} from '../hooks/useMarkdown'; // Import CSS Module import styles from './Text.module.css'; -/** - * Wraps the plain text with appropriate Markdown syntax based on the requested variant. - * - * @param text The plain text to be wrapped. - * @param variant The typography variant (e.g., 'h1', 'caption'). - * @returns The text wrapped in Markdown syntax. - */ -const handleVariant = (text: string, variant?: string): string => { - switch (variant) { - case 'h1': - return `# ${text}`; - case 'h2': - return `## ${text}`; - case 'h3': - return `### ${text}`; - case 'h4': - return `#### ${text}`; - case 'h5': - return `##### ${text}`; - case 'caption': - return `*${text}*`; - default: - return text; - } -}; +const NON_MARKDOWN_VARIANTS = new Set(['h1', 'h2', 'h3', 'h4', 'h5', 'caption']); export const Text = createComponentImplementation(TextApi, ({props}) => { useBasicCatalogStyles(); const text = typeof props.text === 'string' ? props.text : String(props.text ?? ''); - const markdownText = handleVariant(text, props.variant); - const renderedHtml = useMarkdown(markdownText); + const variant = props.variant; + const isKnownVariant = variant !== undefined && NON_MARKDOWN_VARIANTS.has(variant); + + const renderedHtml = useMarkdown(text); const style: React.CSSProperties = { ...getBaseLeafStyle(), ...getWeightStyle(props.weight), }; - const isCaption = props.variant === 'caption'; - const classes = [styles.a2uiText, isCaption ? styles.a2uiCaption : props.variant || 'body']; + const isCaption = variant === 'caption'; + const classes = [styles.a2uiText, isCaption ? styles.a2uiCaption : variant || 'body']; + + if (isKnownVariant) { + const HeadingTag = isCaption ? 'em' : (variant as 'h1' | 'h2' | 'h3' | 'h4' | 'h5'); + if (isCaption) { + return ( + + {text} + + ); + } + return ( +
+ {text} +
+ ); + } + if (renderedHtml === null) { classes.push('no-markdown-renderer'); } const contentProps = renderedHtml !== null ? {dangerouslySetInnerHTML: {__html: renderedHtml}} - : {children: markdownText}; + : {children: text}; - if (isCaption) { - return ; - } return
; }); diff --git a/renderers/react/tests/v0_9/catalog-components.test.tsx b/renderers/react/tests/v0_9/catalog-components.test.tsx index 59afa8bcc..f2cc1d47b 100644 --- a/renderers/react/tests/v0_9/catalog-components.test.tsx +++ b/renderers/react/tests/v0_9/catalog-components.test.tsx @@ -68,7 +68,7 @@ describe('Basic Catalog Components', () => { const {view} = renderA2uiComponent(Text, 't1', {text: 'Title', variant: 'h1'}); const h1 = view.container.querySelector('div.h1'); expect(h1).not.toBeNull(); - expect(h1?.textContent).toBe('# Title'); + expect(h1?.textContent).toBe('Title'); }); }); diff --git a/renderers/react/tests/v0_9/integration-scenarios.test.tsx b/renderers/react/tests/v0_9/integration-scenarios.test.tsx index aeae5d184..98c650898 100644 --- a/renderers/react/tests/v0_9/integration-scenarios.test.tsx +++ b/renderers/react/tests/v0_9/integration-scenarios.test.tsx @@ -38,7 +38,7 @@ describe('Gallery Integration Tests', () => { , ); - expect(screen.getByText('### Markdown Rendering')).toBeInTheDocument(); + expect(screen.getByText('Markdown Rendering')).toBeInTheDocument(); }); it('renders Task Card -> content visibility', async () => { @@ -54,8 +54,8 @@ describe('Gallery Integration Tests', () => { , ); - expect(screen.getByText('### Review pull request')).toBeInTheDocument(); - expect(screen.getByText('*Backend*')).toBeInTheDocument(); + expect(screen.getByText('Review pull request')).toBeInTheDocument(); + expect(screen.getByText('Backend')).toBeInTheDocument(); }); it('handles Login form -> input updates data model', async () => {