@@ -9,6 +9,7 @@ const NODE_MODULES = path.join(ROOT, 'node_modules')
99const ENTRY_SCSS = path . join ( ROOT , 'src' , '_all.scss' )
1010const OUTPUT_DIR = path . join ( ROOT , '.storybook' , 'flavors' )
1111const DIST_DIR = path . join ( ROOT , 'dist' , 'css' )
12+ const DIST_ROOT = path . join ( ROOT , 'dist' )
1213const ICON_FONT_PATH = path . join (
1314 NODE_MODULES ,
1415 '@pepabo-inhouse' ,
@@ -34,6 +35,9 @@ const iconFontFace = (() => {
3435// token declarations no longer live at document level. Required for the
3536// combined (`all.css`) build to avoid the last-flavor-wins cascade conflict
3637// when multiple flavors' `:root { --token: ... }` blocks are concatenated.
38+ // When `prefix` is an empty string, non-:root selectors are left unchanged
39+ // so the output acts as an unscoped baseline (used to give consumers
40+ // styling even without <FlavorProvider>).
3741function prefixPlugin ( prefix , { scopeRoot = false } = { } ) {
3842 return {
3943 postcssPlugin : 'prefix-flavor' ,
@@ -52,15 +56,20 @@ function prefixPlugin(prefix, { scopeRoot = false } = {}) {
5256 if ( sel . startsWith ( ':root' ) ) {
5357 return scopeRoot ? prefix + sel . slice ( ':root' . length ) : sel
5458 }
55- return `${ prefix } ${ sel } `
59+ return prefix ? `${ prefix } ${ sel } ` : sel
5660 } )
5761 } ,
5862 }
5963}
6064prefixPlugin . postcss = true
6165
66+ // Clean stale CSS outputs so renames/removals don't leave leftovers in dist/
67+ fs . rmSync ( DIST_DIR , { recursive : true , force : true } )
68+ fs . rmSync ( path . join ( DIST_ROOT , 'styles.css' ) , { force : true } )
69+
6270fs . mkdirSync ( OUTPUT_DIR , { recursive : true } )
6371fs . mkdirSync ( DIST_DIR , { recursive : true } )
72+ fs . mkdirSync ( DIST_ROOT , { recursive : true } )
6473
6574console . log ( `Building flavor CSS for ${ FLAVORS . length } flavors...` )
6675
@@ -136,18 +145,34 @@ for (const flavor of FLAVORS) {
136145 ] ) . process ( css , { from : undefined } )
137146 combinedParts . push ( combined . css )
138147
148+ // Baseline: emit pepper with no prefix at the top of all.css so consumers
149+ // get styled components even without wrapping with <FlavorProvider>.
150+ // Specificity of `[data-flavor="xxx"] .foo` (0,0,1,1) beats `.foo`
151+ // (0,0,1,0), so an explicit FlavorProvider still overrides the baseline.
152+ if ( flavor === 'pepper' ) {
153+ const baseline = postcss ( [ prefixPlugin ( '' ) ] ) . process ( css , {
154+ from : undefined ,
155+ } )
156+ combinedParts . unshift ( baseline . css )
157+ }
158+
139159 console . log ( ` ✓ ${ flavor } .css` )
140160 } catch ( err ) {
141161 console . error ( ` ✗ ${ flavor } : ${ err . message } ` )
142162 process . exit ( 1 )
143163 }
144164}
145165
146- // Combined CSS: single @font -face at the top, then all 7 flavors
166+ // Combined CSS: @font -face + pepper baseline (unscoped) + 7 flavors scoped.
167+ // Emitted at dist/styles.css to match modern convention
168+ // (e.g. Mantine's `@mantine/core/styles.css`, Radix Themes' `@radix-ui/themes/styles.css`)
169+ // and to signal "this is the default stylesheet consumers should import".
147170fs . writeFileSync (
148- path . join ( DIST_DIR , 'all .css' ) ,
171+ path . join ( DIST_ROOT , 'styles .css' ) ,
149172 iconFontFace + combinedParts . join ( '\n' )
150173)
151- console . log ( ` ✓ all.css (combined, ${ FLAVORS . length } flavors)` )
174+ console . log (
175+ ` ✓ styles.css (pepper baseline + ${ FLAVORS . length } flavors scoped)`
176+ )
152177
153178console . log ( 'Done!' )
0 commit comments