1+ import { useState } from 'react'
2+ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
3+ import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
4+ import dynamic from 'next/dynamic'
5+
6+ interface ComponentProp {
7+ type : string
8+ default : any
9+ }
10+
11+ interface ComponentDefinition {
12+ name : string
13+ variants : string [ ]
14+ props : Record < string , ComponentProp >
15+ }
16+
17+ interface ComponentPlaygroundProps {
18+ component : ComponentDefinition
19+ }
20+
21+ const ComponentPlayground = ( { component } : ComponentPlaygroundProps ) => {
22+ const [ selectedVariant , setSelectedVariant ] = useState ( component . variants [ 0 ] )
23+ const [ props , setProps ] = useState < Record < string , any > > (
24+ Object . entries ( component . props ) . reduce ( ( acc , [ key , value ] ) => ( {
25+ ...acc ,
26+ [ key ] : value . default
27+ } ) , { } )
28+ )
29+
30+ const handlePropChange = ( propName : string , value : any ) => {
31+ setProps ( prev => ( { ...prev , [ propName ] : value } ) )
32+ }
33+
34+ const generateCodeExample = ( ) => {
35+ const propsString = Object . entries ( props )
36+ . map ( ( [ key , value ] ) => `${ key } ="${ value } "` )
37+ . join ( ' ' )
38+ return `<${ component . name } variant="${ selectedVariant } " ${ propsString } />`
39+ }
40+
41+ const DynamicComponent = dynamic ( ( ) => import ( `@/components/ui/${ component . name } ` ) , {
42+ loading : ( ) => < div > Loading component...</ div > ,
43+ ssr : false
44+ } )
45+
46+ return (
47+ < div className = "space-y-4" >
48+ < div data-testid = "component-preview" className = "p-4 border rounded-lg" >
49+ < h3 className = "text-lg font-semibold mb-2" > Preview</ h3 >
50+ < DynamicComponent { ...props } variant = { selectedVariant } />
51+ </ div >
52+
53+ < div className = "space-y-2" >
54+ < label className = "block" >
55+ Variant:
56+ < select
57+ value = { selectedVariant }
58+ onChange = { ( e ) => setSelectedVariant ( e . target . value ) }
59+ className = "ml-2 p-1 border rounded"
60+ >
61+ { component . variants . map ( variant => (
62+ < option key = { variant } value = { variant } > { variant } </ option >
63+ ) ) }
64+ </ select >
65+ </ label >
66+
67+ { Object . entries ( component . props ) . map ( ( [ propName , propDef ] ) => (
68+ < label key = { propName } className = "block" >
69+ { propName } :
70+ { propDef . type === 'boolean' ? (
71+ < input
72+ type = "checkbox"
73+ checked = { props [ propName ] }
74+ onChange = { ( e ) => handlePropChange ( propName , e . target . checked ) }
75+ className = "ml-2"
76+ />
77+ ) : (
78+ < input
79+ type = "text"
80+ value = { props [ propName ] }
81+ onChange = { ( e ) => handlePropChange ( propName , e . target . value ) }
82+ className = "ml-2 p-1 border rounded"
83+ />
84+ ) }
85+ </ label >
86+ ) ) }
87+ </ div >
88+
89+ < div data-testid = "code-example" className = "mt-4" >
90+ < h3 className = "text-lg font-semibold mb-2" > Code Example</ h3 >
91+ < SyntaxHighlighter language = "tsx" style = { vscDarkPlus } >
92+ { generateCodeExample ( ) }
93+ </ SyntaxHighlighter >
94+ </ div >
95+ </ div >
96+ )
97+ }
98+
99+ export default ComponentPlayground
0 commit comments