11import React , { useEffect , useMemo , useState } from 'react' ;
22import type { ThemeDocument } from '@tiny-design/react' ;
3+ import { validateThemeDocument } from '@tiny-design/tokens/validate-theme' ;
34import {
45 Button ,
56 ConfigProvider ,
67 Modal ,
8+ Paragraph ,
79 Segmented ,
810 Select ,
11+ Text ,
912 Textarea ,
10- Typography ,
1113 useTheme ,
1214} from '@tiny-design/react' ;
1315import {
@@ -115,10 +117,16 @@ const ThemeStudioPage = (): React.ReactElement => {
115117 const handleImport = ( ) => {
116118 try {
117119 const parsed = JSON . parse ( importText ) as ThemeDocument ;
118- setDraft ( buildDraftFromThemeDocument ( parsed ) ) ;
120+ const validation = validateThemeDocument ( parsed ) ;
121+ if ( ! validation . valid ) {
122+ setImportError ( validation . errors . join ( '\n' ) ) ;
123+ return ;
124+ }
125+
126+ setDraft ( buildDraftFromThemeDocument ( validation . normalizedDocument as ThemeDocument ) ) ;
119127 setImportVisible ( false ) ;
120128 setImportError ( null ) ;
121- setStatus ( 'Imported theme document' ) ;
129+ setStatus ( validation . warnings . length > 0 ? 'Imported theme document with validation warnings' : 'Imported theme document' ) ;
122130 } catch {
123131 setImportError ( 'Invalid theme document JSON' ) ;
124132 }
@@ -137,7 +145,7 @@ const ThemeStudioPage = (): React.ReactElement => {
137145 >
138146 < div className = "theme-studio__topbar" >
139147 < div className = "theme-studio__topbar-copy" >
140- < Typography . Text className = "theme-studio__eyebrow" > Theme Editor</ Typography . Text >
148+ < Text className = "theme-studio__eyebrow" > Theme Editor</ Text >
141149 < div className = "theme-studio__topbar-meta" >
142150 < span > { activePreset . name } </ span >
143151 < span > { THEME_EDITOR_PRESETS . length } presets</ span >
@@ -194,9 +202,7 @@ const ThemeStudioPage = (): React.ReactElement => {
194202 </ div >
195203 </ div >
196204
197- < div className = { `theme-studio__preview theme-studio__preview_${ draft . mode } ` } >
198- { renderPreview ( draft . activeTemplate , draft . fields , draft . activeSection ) }
199- </ div >
205+ { renderPreview ( draft . activeTemplate , draft . fields , draft . activeSection ) }
200206 </ main >
201207 </ div >
202208
@@ -215,18 +221,18 @@ const ThemeStudioPage = (): React.ReactElement => {
215221 } }
216222 >
217223 < div className = "theme-studio__modal-copy" >
218- < Typography . Paragraph >
224+ < Paragraph >
219225 Paste a Tiny theme document JSON export to replace the current global theme.
220- </ Typography . Paragraph >
221- < Typography . Text type = "secondary" > Preset selection and all editor controls will sync to the imported values.</ Typography . Text >
226+ </ Paragraph >
227+ < Text type = "secondary" > Preset selection and all editor controls will sync to the imported values.</ Text >
222228 </ div >
223229 < Textarea
224230 rows = { 16 }
225231 className = "theme-studio__import-textarea"
226232 value = { importText }
227233 onChange = { ( next ) => setImportText ( next ) }
228234 />
229- { importError ? < Typography . Paragraph className = "theme-studio__error" > { importError } </ Typography . Paragraph > : null }
235+ { importError ? < Paragraph className = "theme-studio__error" > { importError } </ Paragraph > : null }
230236 </ Modal >
231237
232238 < Modal
@@ -247,8 +253,8 @@ const ThemeStudioPage = (): React.ReactElement => {
247253 >
248254 < div className = "theme-studio__code-head" >
249255 < div >
250- < Typography . Text strong > Output</ Typography . Text >
251- < Typography . Text type = "secondary" > { activePreset . name } · { status } </ Typography . Text >
256+ < Text strong > Output</ Text >
257+ < Text type = "secondary" > { activePreset . name } · { status } </ Text >
252258 </ div >
253259 < Segmented
254260 options = { CODE_VIEW_OPTIONS }
0 commit comments