@@ -7,6 +7,8 @@ import { themes } from 'storybook/theming';
77import { globalCss } from '../' ;
88import { FaencyProvider } from '../components/FaencyProvider' ;
99import { darkTheme , lightTheme } from '../stitches.config' ;
10+ import { VanillaExtractThemeProvider } from '../styles/themeContext' ;
11+ import { themes as vanillaThemes } from '../styles/themes.css' ;
1012
1113const channel = addons . getChannel ( ) ;
1214
@@ -17,21 +19,42 @@ const channel = addons.getChannel();
1719const getInitialThemePreference = ( ) => {
1820 if ( typeof window === 'undefined' ) return false ;
1921
20- // Check stored preference first
22+ // Check stored preference
2123 const stored = localStorage . getItem ( 'sb-addon-themes-3' ) ;
2224 if ( stored ) {
2325 try {
2426 const parsed = JSON . parse ( stored ) ;
25- if ( parsed . current === 'dark' ) return true ;
26- } catch ( e ) {
27- // Fall through to system preference
27+ if ( parsed . current ) {
28+ return parsed . current === 'dark' ;
29+ }
30+ } catch ( error ) {
31+ console . warn ( 'Failed to parse Storybook theme preference:' , error ) ;
2832 }
2933 }
3034
31- // Fallback to system preference
35+ // Fallback to system preference only if no stored value or parse error
3236 return window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches ;
3337} ;
3438
39+ // Initialize vanilla-extract theme class immediately on script load
40+ if ( typeof window !== 'undefined' && typeof document !== 'undefined' ) {
41+ const initialTheme = getInitialThemePreference ( ) ? 'dark' : 'light' ;
42+ const themeClass = vanillaThemes [ initialTheme ] [ 'blue' ] ;
43+
44+ function applyInitialTheme ( ) {
45+ Object . values ( vanillaThemes . light ) . forEach ( ( cls ) => document . body . classList . remove ( cls ) ) ;
46+ Object . values ( vanillaThemes . dark ) . forEach ( ( cls ) => document . body . classList . remove ( cls ) ) ;
47+
48+ document . body . classList . add ( themeClass ) ;
49+ }
50+
51+ if ( document . body ) {
52+ applyInitialTheme ( ) ;
53+ } else {
54+ document . addEventListener ( 'DOMContentLoaded' , applyInitialTheme ) ;
55+ }
56+ }
57+
3558export const parameters = {
3659 controls : {
3760 matchers : {
@@ -72,38 +95,14 @@ const globalStyle = globalCss({
7295} ) ;
7396
7497const VanillaProviderWrapper = ( { children, isDark, primaryColor } ) => {
75- const [ Provider , setProvider ] = React . useState ( null ) ;
76- const [ loading , setLoading ] = React . useState ( true ) ;
77-
78- React . useEffect ( ( ) => {
79- import ( '../styles/themeContext' )
80- . then ( ( module ) => {
81- setProvider ( ( ) => module . VanillaExtractThemeProvider ) ;
82- setLoading ( false ) ;
83- } )
84- . catch ( ( err ) => {
85- console . warn ( 'VanillaExtractThemeProvider failed to load:' , err ) ;
86- setLoading ( false ) ;
87- } ) ;
88- } , [ ] ) ;
89-
90- if ( loading ) {
91- return React . createElement ( 'div' , { style : { padding : '24px' } } , 'Loading theme system...' ) ;
92- }
93-
94- if ( Provider ) {
95- return React . createElement (
96- Provider ,
97- {
98- forcedTheme : isDark ? 'dark' : 'light' ,
99- primaryColor,
100- } ,
101- children ,
102- ) ;
103- }
104-
105- // If provider failed to load, just return children (Stitches fallback)
106- return children ;
98+ return React . createElement (
99+ VanillaExtractThemeProvider ,
100+ {
101+ forcedTheme : isDark ? 'dark' : 'light' ,
102+ primaryColor,
103+ } ,
104+ children ,
105+ ) ;
107106} ;
108107
109108export const decorators = [
@@ -120,6 +119,17 @@ export const decorators = [
120119 return ( ) => channel . removeListener ( DARK_MODE_EVENT_NAME , setDark ) ;
121120 } , [ ] ) ;
122121
122+ // Apply vanilla-extract theme class before first render to prevent flash
123+ React . useLayoutEffect ( ( ) => {
124+ const resolvedTheme = isDark ? 'dark' : 'light' ;
125+ const themeClass = vanillaThemes [ resolvedTheme ] [ 'blue' ] ;
126+
127+ Object . values ( vanillaThemes . light ) . forEach ( ( cls ) => document . body . classList . remove ( cls ) ) ;
128+ Object . values ( vanillaThemes . dark ) . forEach ( ( cls ) => document . body . classList . remove ( cls ) ) ;
129+
130+ document . body . classList . add ( themeClass ) ;
131+ } , [ isDark ] ) ;
132+
123133 return (
124134 < VanillaProviderWrapper isDark = { isDark } primaryColor = "blue" >
125135 < FaencyProvider >
0 commit comments