11import { Welcome } from '@ant-design/x' ;
22import XMarkdown , { type ComponentProps } from '@ant-design/x-markdown' ;
3- import { Button , Card , Skeleton , theme } from 'antd' ;
3+ import { Button , Card , Segmented , Skeleton , theme } from 'antd' ;
44import React , { useState } from 'react' ;
55
66const demos = [
@@ -52,8 +52,7 @@ Provides a complete set of **tool APIs**. [Click here for details.](/x-sdks/intr
5252 } ,
5353 {
5454 title : 'Table' ,
55- content : `
56- | Repo | Description |
55+ content : `| Repo | Description |
5756| ------ | ----------- |
5857| @ant-design/x | A React UI library based on the Ant Design system. |
5958| @ant-design/x-markdown | An optimized Markdown rendering solution for streaming content. |
@@ -139,6 +138,19 @@ const StreamDemo: React.FC<{ content: string }> = ({ content }) => {
139138 const [ index , setIndex ] = React . useState ( 0 ) ;
140139 const timer = React . useRef < NodeJS . Timeout | null > ( null ) ;
141140 const contentRef = React . useRef < HTMLDivElement > ( null ) ;
141+ const sourceRef = React . useRef < HTMLDivElement > ( null ) ;
142+
143+ const scrollToBottom = React . useCallback (
144+ ( el : HTMLDivElement | null ) => {
145+ if ( el && index > 0 ) {
146+ const { scrollHeight, clientHeight } = el ;
147+ if ( scrollHeight > clientHeight ) {
148+ el . scrollTo ( { top : scrollHeight , behavior : 'smooth' } ) ;
149+ }
150+ }
151+ } ,
152+ [ index ] ,
153+ ) ;
142154
143155 React . useEffect ( ( ) => {
144156 if ( index >= content . length ) {
@@ -159,32 +171,46 @@ const StreamDemo: React.FC<{ content: string }> = ({ content }) => {
159171 } , [ index ] ) ;
160172
161173 React . useEffect ( ( ) => {
162- if ( contentRef . current && index > 0 && index < content . length ) {
163- const { scrollHeight, clientHeight } = contentRef . current ;
164- if ( scrollHeight > clientHeight ) {
165- contentRef . current . scrollTo ( {
166- top : scrollHeight ,
167- behavior : 'smooth' ,
168- } ) ;
169- }
174+ if ( index > 0 ) {
175+ scrollToBottom ( sourceRef . current ) ;
176+ scrollToBottom ( contentRef . current ) ;
170177 }
171- } , [ index ] ) ;
178+ } , [ index , scrollToBottom ] ) ;
179+
180+ const isLongContent = content . length > 500 ;
181+ const previewMinHeight = isLongContent ? 320 : 160 ;
182+ const previewMaxHeight = isLongContent ? 420 : 280 ;
172183
173184 return (
174- < div style = { { display : 'flex' , gap : 16 , width : '100%' } } >
175- < Card title = "Markdown Source" size = "small" style = { { flex : 1 } } >
185+ < div
186+ style = { {
187+ display : 'flex' ,
188+ gap : 16 ,
189+ width : '100%' ,
190+ minHeight : previewMinHeight ,
191+ maxHeight : previewMaxHeight ,
192+ transition : 'max-height 0.25s ease' ,
193+ } }
194+ >
195+ < Card
196+ title = "Markdown Source"
197+ size = "small"
198+ style = { { flex : 1 , display : 'flex' , flexDirection : 'column' , minWidth : 0 } }
199+ styles = { { body : { flex : 1 , minHeight : 0 , display : 'flex' , flexDirection : 'column' } } }
200+ >
176201 < div
202+ ref = { sourceRef }
177203 style = { {
178- background : '#f5f5f5' ,
204+ flex : 1 ,
205+ minHeight : 0 ,
206+ background : 'var(--ant-color-fill-quaternary)' ,
179207 padding : 12 ,
180- borderRadius : 4 ,
181- fontSize : 13 ,
182- fontFamily : 'monospace' ,
208+ borderRadius : 6 ,
183209 whiteSpace : 'pre-wrap' ,
184210 wordBreak : 'break-word' ,
185- margin : 0 ,
186- height : 600 ,
187211 overflow : 'auto' ,
212+ fontSize : 12 ,
213+ lineHeight : 1.5 ,
188214 } }
189215 >
190216 { content . slice ( 0 , index ) }
@@ -194,26 +220,31 @@ const StreamDemo: React.FC<{ content: string }> = ({ content }) => {
194220 < Card
195221 title = "Rendered Output"
196222 size = "small"
197- style = { { flex : 1 , overflow : 'scroll' } }
223+ style = { { flex : 1 , display : 'flex' , flexDirection : 'column' , minWidth : 0 } }
224+ styles = { { body : { flex : 1 , minHeight : 0 , display : 'flex' , flexDirection : 'column' } } }
198225 extra = {
199226 < Button
200- type = "primary"
201- onClick = { ( ) => {
227+ onClick = { ( e ) => {
228+ e . preventDefault ( ) ;
202229 setIndex ( 0 ) ;
203230 setHasNextChunk ( true ) ;
204231 } }
232+ size = "small"
205233 >
206234 Re-Render
207235 </ Button >
208236 }
209237 >
210238 < div
239+ ref = { contentRef }
211240 style = { {
212- border : '1px solid #f0f0f0' ,
213- borderRadius : 4 ,
241+ flex : 1 ,
242+ minHeight : 0 ,
243+ overflow : 'auto' ,
214244 padding : 12 ,
215- maxHeight : 800 ,
216- overflow : 'scroll' ,
245+ borderRadius : 6 ,
246+ border : '1px solid var(--ant-color-border-secondary)' ,
247+ background : 'var(--ant-color-bg-container)' ,
217248 } }
218249 >
219250 < XMarkdown
@@ -243,18 +274,15 @@ const App = () => {
243274 const [ currentDemo , setCurrentDemo ] = useState ( 0 ) ;
244275
245276 return (
246- < div style = { { padding : 24 } } >
247- { demos . map ( ( demo , index ) => (
248- < Button
249- key = { index }
250- type = { currentDemo === index ? 'primary' : 'default' }
251- onClick = { ( ) => setCurrentDemo ( index ) }
252- style = { { marginRight : 8 , marginBottom : 8 } }
253- >
254- { demo . title }
255- </ Button >
256- ) ) }
257-
277+ < div style = { { maxWidth : 960 , margin : '0 auto' } } >
278+ < div style = { { marginBottom : 16 } } >
279+ < Segmented
280+ value = { currentDemo }
281+ onChange = { ( v ) => setCurrentDemo ( Number ( v ) ) }
282+ options = { demos . map ( ( demo , index ) => ( { label : demo . title , value : index } ) ) }
283+ block
284+ />
285+ </ div >
258286 < StreamDemo key = { currentDemo } content = { demos [ currentDemo ] . content } />
259287 </ div >
260288 ) ;
0 commit comments