@@ -20,10 +20,31 @@ const ensureHighlighter = (): Promise<any> => {
2020 return highlighterReady ;
2121} ;
2222
23- const htmlStyleToCSS = ( htmlStyle : Record < string , string > ) : string =>
24- Object . entries ( htmlStyle )
25- . map ( ( [ k , v ] ) => `${ k } :${ v } ` )
26- . join ( ";" ) ;
23+ /**
24+ * Build an inline style string from token.htmlStyle.
25+ * Redirects shiki's direct CSS properties to CSS custom properties
26+ * so our stylesheet can switch themes via media queries / .dark class.
27+ *
28+ * Light color → --shiki-light (used by CSS default)
29+ * Dark color → --shiki-dark (used by CSS dark mode)
30+ */
31+ const tokenToStyle = ( token : any ) : string | undefined => {
32+ if ( ! token . htmlStyle ) return undefined ;
33+
34+ const parts : string [ ] = [ ] ;
35+ for ( const [ key , value ] of Object . entries ( token . htmlStyle ) ) {
36+ if ( key === "color" ) {
37+ // Redirect direct color to CSS var — our CSS sets `color: var(--shiki-light)`
38+ parts . push ( `--shiki-light:${ value } ` ) ;
39+ } else if ( key === "background-color" ) {
40+ parts . push ( `--shiki-light-bg:${ value } ` ) ;
41+ } else {
42+ // Pass through CSS custom properties like --shiki-dark
43+ parts . push ( `${ key } :${ value } ` ) ;
44+ }
45+ }
46+ return parts . length > 0 ? parts . join ( ";" ) : undefined ;
47+ } ;
2748
2849export const rehypeShiki = ( options : RehypeShikiOptions = { } ) => {
2950 const themes = options . themes ?? [ "github-light" , "github-dark" ] ;
@@ -36,7 +57,6 @@ export const rehypeShiki = (options: RehypeShikiOptions = {}) => {
3657 return ;
3758 }
3859
39- // Collect pre > code pairs
4060 const codeNodes : Array < { pre : any ; code : any ; lang : string } > = [ ] ;
4161 visit ( tree , "element" , ( node : any ) => {
4262 if ( node . tagName !== "pre" ) return ;
@@ -49,7 +69,6 @@ export const rehypeShiki = (options: RehypeShikiOptions = {}) => {
4969 codeNodes . push ( { pre : node , code, lang } ) ;
5070 } ) ;
5171
52- // Load languages on demand, skip invalid ones
5372 for ( const { lang } of codeNodes ) {
5473 if ( ! lang || lang === "text" ) continue ;
5574 const loaded = h . getLoadedLanguages ( ) ;
@@ -76,14 +95,29 @@ export const rehypeShiki = (options: RehypeShikiOptions = {}) => {
7695 themes : { light : themes [ 0 ] , dark : themes [ 1 ] } ,
7796 } ) ;
7897
79- // Set background color on <pre> so code blocks get shiki's bg
80- // even when the page has a dark background
81- if ( result . bg ) {
98+ // Set CSS custom properties on <pre> for theme switching.
99+ // Users override via .svelte-streamdown pre or @media queries.
100+ const preStyleParts : string [ ] = [ ] ;
101+ if ( result . bg ) preStyleParts . push ( `--shiki-light-bg:${ result . bg } ` ) ;
102+ if ( result . fg ) preStyleParts . push ( `--shiki-light-fg:${ result . fg } ` ) ;
103+ // result.rootStyle contains --shiki-dark-bg from the dark theme
104+ if ( result . rootStyle ) {
105+ for ( const decl of result . rootStyle . split ( ";" ) ) {
106+ const idx = decl . indexOf ( ":" ) ;
107+ if ( idx > 0 ) {
108+ const prop = decl . slice ( 0 , idx ) . trim ( ) ;
109+ const val = decl . slice ( idx + 1 ) . trim ( ) ;
110+ if ( prop && val ) preStyleParts . push ( `${ prop } :${ val } ` ) ;
111+ }
112+ }
113+ }
114+
115+ if ( preStyleParts . length > 0 ) {
82116 if ( ! pre . properties ) pre . properties = { } ;
83- pre . properties . style = `background-color: ${ result . bg } ` ;
117+ pre . properties . style = preStyleParts . join ( ";" ) ;
84118 }
85119
86- // Highlight tokens with dual-theme CSS vars
120+ // Highlight tokens
87121 code . children = result . tokens . map ( ( line : any ) => ( {
88122 type : "element" ,
89123 tagName : "span" ,
@@ -92,9 +126,7 @@ export const rehypeShiki = (options: RehypeShikiOptions = {}) => {
92126 type : "element" ,
93127 tagName : "span" ,
94128 properties : {
95- style : token . htmlStyle
96- ? htmlStyleToCSS ( token . htmlStyle )
97- : undefined ,
129+ style : tokenToStyle ( token ) ,
98130 } ,
99131 children : [ { type : "text" , value : token . content } ] ,
100132 } ) ) ,
0 commit comments