Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7ea8a22

Browse files
authored
fix: add type-safety for Storybook preview.jsx config file (#14671)
* fix: add type-safety to Storybook preview.jsx file* fix: add clarifying comments* fix: add type-safety to preview config
1 parentc6bc741 commit7ea8a22

File tree

1 file changed

+131
-100
lines changed

1 file changed

+131
-100
lines changed

‎site/.storybook/preview.jsx

Lines changed: 131 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,155 @@
1+
//@ts-check
2+
/**
3+
*@file Defines the main configuration file for all of our Storybook tests.
4+
* This file must be a JSX/JS file, but we can at least add some type safety via
5+
* the ts-check directive.
6+
*@see {@link https://storybook.js.org/docs/configure#configure-story-rendering}
7+
*
8+
*@typedef {import("react").ReactElement} ReactElement
9+
*@typedef {import("react").PropsWithChildren} PropsWithChildren
10+
*@typedef {import("react").FC<PropsWithChildren>} FC
11+
*
12+
*@typedef {import("@storybook/react").StoryContext} StoryContext
13+
*@typedef {import("@storybook/react").Preview} Preview
14+
*
15+
*@typedef {(Story: FC, Context: StoryContext) => React.JSX.Element} Decorator A
16+
* Storybook decorator function used to inject baseline data dependencies into
17+
* our React components during testing.
18+
*/
19+
import{ThemeProviderasEmotionThemeProvider}from"@emotion/react";
120
importCssBaselinefrom"@mui/material/CssBaseline";
221
import{
3-
StyledEngineProvider,
4-
ThemeProviderasMuiThemeProvider,
22+
ThemeProviderasMuiThemeProvider,
23+
StyledEngineProvider,
524
}from"@mui/material/styles";
6-
import{ThemeProviderasEmotionThemeProvider}from"@emotion/react";
725
import{DecoratorHelpers}from"@storybook/addon-themes";
8-
import{withRouter}from"storybook-addon-remix-react-router";
9-
import{StrictMode}from"react";
10-
import{parseQueryArgs,QueryClient,QueryClientProvider}from"react-query";
26+
importisChromaticfrom"chromatic/isChromatic";
27+
importReact,{StrictMode}from"react";
1128
import{HelmetProvider}from"react-helmet-async";
12-
importthemesfrom"theme";
29+
import{parseQueryArgs,QueryClient,QueryClientProvider}from"react-query";
30+
import{withRouter}from"storybook-addon-remix-react-router";
1331
import"theme/globalFonts";
14-
importisChromaticfrom"chromatic/isChromatic";
32+
importthemesfrom"../src/theme";
1533

1634
DecoratorHelpers.initializeThemeState(Object.keys(themes),"dark");
1735

18-
exportconstdecorators=[
19-
withRouter,
20-
withQuery,
21-
(Story)=>{
22-
return(
23-
<HelmetProvider>
24-
<Story/>
25-
</HelmetProvider>
26-
);
27-
},
28-
(Story,context)=>{
29-
constselectedTheme=DecoratorHelpers.pluckThemeFromContext(context);
30-
const{ themeOverride}=DecoratorHelpers.useThemeParameters();
31-
constselected=themeOverride||selectedTheme||"dark";
32-
33-
return(
34-
<StrictMode>
35-
<StyledEngineProviderinjectFirst>
36-
<MuiThemeProvidertheme={themes[selected]}>
37-
<EmotionThemeProvidertheme={themes[selected]}>
38-
<CssBaseline/>
39-
<Story/>
40-
</EmotionThemeProvider>
41-
</MuiThemeProvider>
42-
</StyledEngineProvider>
43-
</StrictMode>
44-
);
45-
},
46-
];
36+
/**@type {readonly Decorator[]} */
37+
exportconstdecorators=[withRouter,withQuery,withHelmet,withTheme];
4738

39+
/**@type {Preview["parameters"]} */
4840
exportconstparameters={
49-
options:{
50-
storySort:{
51-
method:"alphabetical",
52-
order:["design","pages","modules","components"],
53-
locales:"en-US",
54-
},
55-
},
56-
controls:{
57-
expanded:true,
58-
matchers:{
59-
color:/(background|color)$/i,
60-
date:/Date$/,
61-
},
62-
},
63-
viewport:{
64-
viewports:{
65-
ipad:{
66-
name:"iPad Mini",
67-
styles:{
68-
height:"1024px",
69-
width:"768px",
70-
},
71-
type:"tablet",
72-
},
73-
terminal:{
74-
name:"Terminal",
75-
styles:{
76-
height:"400",
77-
width:"400",
78-
},
79-
},
80-
},
81-
},
41+
options:{
42+
storySort:{
43+
method:"alphabetical",
44+
order:["design","pages","modules","components"],
45+
locales:"en-US",
46+
},
47+
},
48+
controls:{
49+
expanded:true,
50+
matchers:{
51+
color:/(background|color)$/i,
52+
date:/Date$/,
53+
},
54+
},
55+
viewport:{
56+
viewports:{
57+
ipad:{
58+
name:"iPad Mini",
59+
styles:{
60+
height:"1024px",
61+
width:"768px",
62+
},
63+
type:"tablet",
64+
},
65+
terminal:{
66+
name:"Terminal",
67+
styles:{
68+
height:"400",
69+
width:"400",
70+
},
71+
},
72+
},
73+
},
8274
};
8375

76+
/**
77+
* There's a mismatch on the React Helmet return type that causes issues when
78+
* mounting the component in JS files only. Have to do type assertion, which is
79+
* especially ugly in JSDoc
80+
*/
81+
constSafeHelmetProvider=/**@type {FC} */(
82+
/**@type {unknown} */(HelmetProvider)
83+
);
84+
85+
/**@type {Decorator} */
86+
functionwithHelmet(Story){
87+
return(
88+
<SafeHelmetProvider>
89+
<Story/>
90+
</SafeHelmetProvider>
91+
);
92+
}
93+
94+
/**@type {Decorator} */
8495
functionwithQuery(Story,{ parameters}){
85-
constqueryClient=newQueryClient({
86-
defaultOptions:{
87-
queries:{
88-
staleTime:Infinity,
89-
retry:false,
90-
},
91-
},
92-
});
96+
constqueryClient=newQueryClient({
97+
defaultOptions:{
98+
queries:{
99+
staleTime:Number.POSITIVE_INFINITY,
100+
retry:false,
101+
},
102+
},
103+
});
104+
105+
if(parameters.queries){
106+
for(constqueryofparameters.queries){
107+
if(query.datainstanceofError){
108+
// This is copied from setQueryData() but sets the error.
109+
constcache=queryClient.getQueryCache();
110+
constparsedOptions=parseQueryArgs(query.key);
111+
constdefaultedOptions=queryClient.defaultQueryOptions(parsedOptions);
112+
constcachedQuery=cache.build(queryClient,defaultedOptions);
113+
// Set manual data so react-query will not try to refetch.
114+
cachedQuery.setData(undefined,{manual:true});
115+
cachedQuery.setState({error:query.data});
116+
}else{
117+
queryClient.setQueryData(query.key,query.data);
118+
}
119+
}
120+
}
121+
122+
return(
123+
<QueryClientProviderclient={queryClient}>
124+
<Story/>
125+
</QueryClientProvider>
126+
);
127+
}
93128

94-
if(parameters.queries){
95-
parameters.queries.forEach((query)=>{
96-
if(query.datainstanceofError){
97-
// This is copied from setQueryData() but sets the error.
98-
constcache=queryClient.getQueryCache();
99-
constparsedOptions=parseQueryArgs(query.key)
100-
constdefaultedOptions=queryClient.defaultQueryOptions(parsedOptions)
101-
constcachedQuery=cache.build(queryClient,defaultedOptions);
102-
// Set manual data so react-query will not try to refetch.
103-
cachedQuery.setData(undefined,{manual:true});
104-
cachedQuery.setState({error:query.data});
105-
}else{
106-
queryClient.setQueryData(query.key,query.data);
107-
}
108-
});
109-
}
129+
/**@type {Decorator} */
130+
functionwithTheme(Story,context){
131+
constselectedTheme=DecoratorHelpers.pluckThemeFromContext(context);
132+
const{ themeOverride}=DecoratorHelpers.useThemeParameters();
133+
constselected=themeOverride||selectedTheme||"dark";
110134

111-
return(
112-
<QueryClientProviderclient={queryClient}>
113-
<Story/>
114-
</QueryClientProvider>
115-
);
135+
return(
136+
<StrictMode>
137+
<StyledEngineProviderinjectFirst>
138+
<MuiThemeProvidertheme={themes[selected]}>
139+
<EmotionThemeProvidertheme={themes[selected]}>
140+
<CssBaseline/>
141+
<Story/>
142+
</EmotionThemeProvider>
143+
</MuiThemeProvider>
144+
</StyledEngineProvider>
145+
</StrictMode>
146+
);
116147
}
117148

118149
// Try to fix storybook rendering fonts inconsistently
119150
// https://www.chromatic.com/docs/font-loading/#solution-c-check-fonts-have-loaded-in-a-loader
120151
constfontLoader=async()=>({
121-
fonts:awaitdocument.fonts.ready,
152+
fonts:awaitdocument.fonts.ready,
122153
});
123154

124155
exportconstloaders=isChromatic()&&document.fonts ?[fontLoader] :[];

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp