11import { Context , type StyleDecoder , type Stylesheet } from '@pandacss/core'
2- import { PandaError } from '@pandacss/shared'
2+ import { dashCase , PandaError } from '@pandacss/shared'
33import type { ArtifactId , CssArtifactType , LoadConfigResult } from '@pandacss/types'
44import { match } from 'ts-pattern'
55import { generateArtifacts } from './artifacts'
@@ -9,6 +9,29 @@ import { generateParserCss } from './artifacts/css/parser-css'
99import { generateResetCss } from './artifacts/css/reset-css'
1010import { generateStaticCss } from './artifacts/css/static-css'
1111import { generateTokenCss } from './artifacts/css/token-css'
12+ import { getThemeCss } from './artifacts/js/themes'
13+
14+ export interface SplitCssArtifact {
15+ type : 'layer' | 'recipe' | 'theme'
16+ name : string
17+ file : string
18+ code : string
19+ /** Directory relative to styles/ */
20+ dir ?: string
21+ }
22+
23+ export interface SplitCssResult {
24+ /** Layer CSS files (reset, global, tokens, utilities) */
25+ layers : SplitCssArtifact [ ]
26+ /** Recipe CSS files */
27+ recipes : SplitCssArtifact [ ]
28+ /** Theme CSS files (not auto-imported) */
29+ themes : SplitCssArtifact [ ]
30+ /** Content for recipes/index.css */
31+ recipesIndex : string
32+ /** Content for main styles.css */
33+ index : string
34+ }
1235
1336export class Generator extends Context {
1437 constructor ( conf : LoadConfigResult ) {
@@ -65,4 +88,111 @@ export class Generator extends Context {
6588
6689 return css
6790 }
91+
92+ /**
93+ * Get CSS for a specific layer from the stylesheet
94+ */
95+ getLayerCss = ( sheet : Stylesheet , layer : 'reset' | 'base' | 'tokens' | 'recipes' | 'utilities' ) => {
96+ return sheet . getLayerCss ( layer )
97+ }
98+
99+ /**
100+ * Get CSS for a specific recipe
101+ */
102+ getRecipeCss = ( recipeName : string ) => {
103+ const sheet = this . createSheet ( )
104+ const decoder = this . decoder . collect ( this . encoder )
105+ sheet . processDecoderForRecipe ( decoder , recipeName )
106+ return sheet . getLayerCss ( 'recipes' )
107+ }
108+
109+ /**
110+ * Get all recipe names from the decoder
111+ */
112+ getRecipeNames = ( ) => {
113+ const decoder = this . decoder . collect ( this . encoder )
114+ return Array . from ( decoder . recipes . keys ( ) )
115+ }
116+
117+ /**
118+ * Get all split CSS artifacts for the stylesheet
119+ * Used when --splitting flag is enabled
120+ */
121+ getSplitCssArtifacts = ( sheet : Stylesheet ) : SplitCssResult => {
122+ const layerNames = this . config . layers as Record < string , string >
123+ const decoder = this . decoder . collect ( this . encoder )
124+
125+ // Layer artifacts
126+ const layerDefs = [
127+ { name : 'reset' , file : 'reset.css' , css : sheet . getLayerCss ( 'reset' ) } ,
128+ { name : 'global' , file : 'global.css' , css : sheet . getLayerCss ( 'base' ) } ,
129+ { name : 'tokens' , file : 'tokens.css' , css : sheet . getLayerCss ( 'tokens' ) } ,
130+ { name : 'utilities' , file : 'utilities.css' , css : sheet . getLayerCss ( 'utilities' ) } ,
131+ ]
132+
133+ const layers : SplitCssArtifact [ ] = layerDefs
134+ . filter ( ( l ) => l . css . trim ( ) )
135+ . map ( ( l ) => ( {
136+ type : 'layer' as const ,
137+ name : l . name ,
138+ file : l . file ,
139+ code : l . css ,
140+ } ) )
141+
142+ // Recipe artifacts
143+ const recipes : SplitCssArtifact [ ] = [ ]
144+ for ( const recipeName of decoder . recipes . keys ( ) ) {
145+ const recipeSheet = this . createSheet ( )
146+ recipeSheet . processDecoderForRecipe ( decoder , recipeName )
147+ const code = recipeSheet . getLayerCss ( 'recipes' )
148+ if ( code . trim ( ) ) {
149+ recipes . push ( {
150+ type : 'recipe' ,
151+ name : recipeName ,
152+ file : `${ dashCase ( recipeName ) } .css` ,
153+ code,
154+ dir : 'recipes' ,
155+ } )
156+ }
157+ }
158+
159+ // Theme artifacts (not auto-imported in styles.css)
160+ const themes : SplitCssArtifact [ ] = [ ]
161+ if ( this . config . themes ) {
162+ for ( const themeName of Object . keys ( this . config . themes ) ) {
163+ const css = getThemeCss ( this , themeName )
164+ if ( css . trim ( ) ) {
165+ themes . push ( {
166+ type : 'theme' ,
167+ name : themeName ,
168+ file : `${ dashCase ( themeName ) } .css` ,
169+ code : `@layer ${ layerNames . tokens } {\n${ css } \n}` ,
170+ dir : 'themes' ,
171+ } )
172+ }
173+ }
174+ }
175+
176+ // Build recipes/index.css content
177+ const recipesIndex = recipes . map ( ( r ) => `@import './${ r . file } ';` ) . join ( '\n' )
178+
179+ // Build main styles.css content
180+ const layerOrder = [ layerNames . reset , layerNames . base , layerNames . tokens , layerNames . recipes , layerNames . utilities ]
181+ const imports = [ `@layer ${ layerOrder . join ( ', ' ) } ;` , '' ]
182+
183+ for ( const layer of layers ) {
184+ imports . push ( `@import './styles/${ layer . file } ';` )
185+ }
186+ if ( recipes . length ) {
187+ imports . push ( `@import './styles/recipes/index.css';` )
188+ }
189+
190+ return {
191+ layers,
192+ recipes,
193+ themes,
194+ recipesIndex,
195+ index : imports . join ( '\n' ) ,
196+ }
197+ }
68198}
0 commit comments