11import { renderStyles , tasty } from '@tenphi/tasty' ;
22import copy from 'clipboard-copy' ;
3- import { useCallback , useMemo } from 'react' ;
3+ import { useCallback , useEffect , useMemo , useRef } from 'react' ;
44
55import { Button } from '../../components/actions/Button' ;
66import { Layout } from '../../components/content/Layout' ;
77import { PrismCode } from '../../components/content/PrismCode/PrismCode' ;
88import { useToast } from '../../components/overlays/Toast' ;
99import { CopyIcon } from '../../icons' ;
1010
11- import type { StyleResult , Styles } from '@tenphi/tasty' ;
11+ import type { KeyframesSteps , StyleResult , Styles } from '@tenphi/tasty' ;
1212
1313const OutputContent = tasty ( {
1414 styles : {
@@ -23,6 +23,31 @@ const OutputContent = tasty({
2323
2424export interface PlaygroundOutputProps {
2525 styles : Styles ;
26+ resetKey ?: number | string ;
27+ }
28+
29+ function formatKeyframes ( keyframes : Record < string , KeyframesSteps > ) : string {
30+ const blocks : string [ ] = [ ] ;
31+
32+ for ( const [ name , steps ] of Object . entries ( keyframes ) ) {
33+ const stepLines : string [ ] = [ ] ;
34+
35+ for ( const [ step , value ] of Object . entries ( steps ) ) {
36+ if ( typeof value === 'string' ) {
37+ stepLines . push ( ` ${ step } {\n ${ value } ;\n }` ) ;
38+ } else {
39+ const decls = Object . entries ( value )
40+ . map ( ( [ prop , val ] ) => `${ prop } : ${ val } ` )
41+ . join ( ';\n ' ) ;
42+
43+ stepLines . push ( ` ${ step } {\n ${ decls } ;\n }` ) ;
44+ }
45+ }
46+
47+ blocks . push ( `@keyframes ${ name } {\n${ stepLines . join ( '\n' ) } \n}` ) ;
48+ }
49+
50+ return blocks . join ( '\n\n' ) ;
2651}
2752
2853function formatStyleResults ( results : StyleResult [ ] ) : string {
@@ -76,18 +101,34 @@ function formatStyleResults(results: StyleResult[]): string {
76101 return lines . join ( '\n\n' ) ;
77102}
78103
79- export function PlaygroundOutput ( { styles } : PlaygroundOutputProps ) {
104+ export function PlaygroundOutput ( { styles, resetKey } : PlaygroundOutputProps ) {
80105 const toast = useToast ( ) ;
106+ const scrollRef = useRef < HTMLDivElement > ( null ) ;
107+
108+ useEffect ( ( ) => {
109+ scrollRef . current ?. scrollTo ( 0 , 0 ) ;
110+ } , [ resetKey ] ) ;
81111
82112 const cssOutput = useMemo ( ( ) => {
83113 if ( ! styles || Object . keys ( styles ) . length === 0 ) {
84114 return '/* Enter styles in the editor to see generated CSS */' ;
85115 }
86116
87117 try {
88- // Use a demo selector for display purposes
118+ const parts : string [ ] = [ ] ;
119+
120+ const keyframesDef = styles [ '@keyframes' ] as
121+ | Record < string , KeyframesSteps >
122+ | undefined ;
123+
124+ if ( keyframesDef && typeof keyframesDef === 'object' ) {
125+ parts . push ( formatKeyframes ( keyframesDef ) ) ;
126+ }
127+
89128 const results = renderStyles ( styles , '.demo' ) ;
90- return formatStyleResults ( results as StyleResult [ ] ) ;
129+ parts . push ( formatStyleResults ( results as StyleResult [ ] ) ) ;
130+
131+ return parts . filter ( Boolean ) . join ( '\n\n' ) ;
91132 } catch ( e ) {
92133 return `/* Error generating CSS: ${ ( e as Error ) . message } */` ;
93134 }
@@ -111,7 +152,7 @@ export function PlaygroundOutput({ styles }: PlaygroundOutputProps) {
111152 />
112153 </ Layout . Toolbar >
113154 < Layout . Content padding = { 0 } >
114- < OutputContent >
155+ < OutputContent ref = { scrollRef } >
115156 < PrismCode code = { cssOutput } language = "css" />
116157 </ OutputContent >
117158 </ Layout . Content >
0 commit comments