Skip to content

Commit 446b41d

Browse files
committed
fix: more perf things
1 parent 83c785d commit 446b41d

File tree

14 files changed

+382
-193
lines changed

14 files changed

+382
-193
lines changed

.eslintrc.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,11 @@ module.exports = {
55
'react-native/no-inline-styles': 'off',
66
'react/react-in-jsx-scope': 'off',
77
curly: ['error', 'multi-line'],
8+
'react-hooks/exhaustive-deps': [
9+
'error',
10+
{
11+
additionalHooks: 'useStyle',
12+
},
13+
],
814
},
915
};

packages/react-native-ui/src/Layout.tsx

Lines changed: 147 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { addons } from '@storybook/core/manager-api';
33
import { type API_IndexHash, type Args, type StoryContext } from '@storybook/core/types';
44
import type { ReactRenderer } from '@storybook/react';
55
import { styled, useTheme } from '@storybook/react-native-theming';
6-
import { ReactNode, useRef, useState } from 'react';
7-
import { ScrollView, Text, TouchableOpacity, View } from 'react-native';
6+
import { ReactNode, useRef, useState, useCallback } from 'react';
7+
import { ScrollView, Text, TouchableOpacity, View, ViewStyle } from 'react-native';
88
import { useSafeAreaInsets } from 'react-native-safe-area-context';
99
import { IconButton } from './IconButton';
1010
import { useLayout } from './LayoutProvider';
@@ -18,6 +18,39 @@ import { BottomBarToggleIcon } from './icon/BottomBarToggleIcon';
1818
import { CloseFullscreenIcon } from './icon/CloseFullscreenIcon';
1919
import { FullscreenIcon } from './icon/FullscreenIcon';
2020
import { MenuIcon } from './icon/MenuIcon';
21+
import { useStyle } from './util/useStyle';
22+
23+
const desktopLogoContainer = {
24+
flexDirection: 'row',
25+
alignItems: 'center',
26+
paddingTop: 10,
27+
paddingLeft: 16,
28+
paddingBottom: 4,
29+
paddingRight: 10,
30+
justifyContent: 'space-between',
31+
} satisfies ViewStyle;
32+
33+
const desktopContentContainerStyle = { flex: 1 } satisfies ViewStyle;
34+
35+
const desktopContentStyle = { flex: 1, overflow: 'hidden' } satisfies ViewStyle;
36+
37+
const mobileContentStyle = { flex: 1, overflow: 'hidden' } satisfies ViewStyle;
38+
39+
const placeholderObject = {};
40+
41+
const placeholderArray = [];
42+
43+
const iconFloatRightStyle = { marginLeft: 'auto' } satisfies ViewStyle;
44+
45+
const navButtonStyle = { flexShrink: 1 } satisfies ViewStyle;
46+
47+
const navButtonHitSlop = { bottom: 10, left: 10, right: 10, top: 10 };
48+
49+
const mobileMenuDrawerContentStyle = {
50+
paddingLeft: 16,
51+
paddingTop: 4,
52+
paddingBottom: 4,
53+
} satisfies ViewStyle;
2154

2255
export const Layout = ({
2356
storyHash,
@@ -46,58 +79,114 @@ export const Layout = ({
4679

4780
const [uiHidden, setUiHidden] = useState(false);
4881

82+
const desktopContainerStyle = useStyle(
83+
() => ({
84+
flex: 1,
85+
paddingTop: insets.top,
86+
backgroundColor: theme.background.content,
87+
flexDirection: 'row',
88+
}),
89+
[theme.background.content, insets.top]
90+
);
91+
92+
const desktopSidebarStyle = useStyle(
93+
() => ({
94+
width: desktopSidebarOpen ? 240 : undefined,
95+
padding: desktopSidebarOpen ? 0 : 10,
96+
borderColor: theme.appBorderColor,
97+
borderRightWidth: 1,
98+
}),
99+
[desktopSidebarOpen, theme.appBorderColor]
100+
);
101+
102+
const desktopScrollViewContentContainerStyle = useStyle(
103+
() => ({
104+
paddingBottom: insets.bottom,
105+
}),
106+
[insets.bottom]
107+
);
108+
109+
const desktopAddonsPanelStyle = useStyle(
110+
() => ({
111+
height: desktopAddonsPanelOpen ? 300 : undefined,
112+
borderTopWidth: 1,
113+
borderColor: theme.appBorderColor,
114+
paddingTop: desktopAddonsPanelOpen ? 4 : 0,
115+
padding: desktopAddonsPanelOpen ? 0 : 10,
116+
}),
117+
[desktopAddonsPanelOpen, theme.appBorderColor]
118+
);
119+
120+
const mobileContainerStyle = useStyle(
121+
() => ({
122+
flex: 1,
123+
paddingTop: story?.parameters?.noSafeArea ? 0 : insets.top,
124+
backgroundColor: theme.background.content,
125+
}),
126+
[theme.background.content, insets.top, story?.parameters?.noSafeArea]
127+
);
128+
129+
const fullScreenButtonStyle = useStyle(
130+
() => ({
131+
position: 'absolute',
132+
bottom: uiHidden ? 56 + insets.bottom : 16,
133+
right: 16,
134+
backgroundColor: theme.background.content,
135+
padding: 4,
136+
borderRadius: 4,
137+
borderWidth: 1,
138+
borderColor: theme.appBorderColor,
139+
}),
140+
[uiHidden, insets.bottom, theme.background.content, theme.appBorderColor]
141+
);
142+
143+
const containerStyle = useStyle(
144+
() => ({
145+
marginBottom: insets.bottom,
146+
}),
147+
[insets.bottom]
148+
);
149+
150+
const navButtonTextStyle = useStyle(
151+
() => ({
152+
flexShrink: 1,
153+
color: theme.color.defaultText,
154+
}),
155+
[theme.color.defaultText]
156+
);
157+
158+
const openMobileMenu = useCallback(() => {
159+
mobileMenuDrawerRef.current.setMobileMenuOpen(true);
160+
}, [mobileMenuDrawerRef]);
161+
162+
const setSelection = useCallback(({ storyId: newStoryId }: { storyId: string }) => {
163+
const channel = addons.getChannel();
164+
165+
channel.emit(SET_CURRENT_STORY, { storyId: newStoryId });
166+
}, []);
167+
49168
if (isDesktop) {
50169
return (
51-
<View
52-
style={{
53-
flex: 1,
54-
paddingTop: insets.top,
55-
backgroundColor: theme.background.content,
56-
flexDirection: 'row',
57-
}}
58-
>
59-
<View
60-
style={{
61-
width: desktopSidebarOpen ? 240 : undefined,
62-
padding: desktopSidebarOpen ? 0 : 10,
63-
borderColor: theme.appBorderColor,
64-
borderRightWidth: 1,
65-
}}
66-
>
170+
<View style={desktopContainerStyle}>
171+
<View style={desktopSidebarStyle}>
67172
{desktopSidebarOpen ? (
68173
<ScrollView
69174
keyboardShouldPersistTaps="handled"
70-
contentContainerStyle={{
71-
paddingBottom: insets.bottom,
72-
}}
175+
contentContainerStyle={desktopScrollViewContentContainerStyle}
73176
>
74-
<View
75-
style={{
76-
flexDirection: 'row',
77-
alignItems: 'center',
78-
paddingTop: 10,
79-
paddingLeft: 16,
80-
paddingBottom: 4,
81-
paddingRight: 10,
82-
justifyContent: 'space-between',
83-
}}
84-
>
177+
<View style={desktopLogoContainer}>
85178
<StorybookLogo theme={theme} />
86179

87180
<IconButton onPress={() => setDesktopSidebarOpen(false)} Icon={MenuIcon} />
88181
</View>
89182

90183
<Sidebar
91-
extra={[]}
184+
extra={placeholderArray}
92185
previewInitialized
93186
indexError={undefined}
94-
refs={{}}
95-
setSelection={({ storyId: newStoryId }) => {
96-
const channel = addons.getChannel();
97-
98-
channel.emit(SET_CURRENT_STORY, { storyId: newStoryId });
99-
}}
100-
status={{}}
187+
refs={placeholderObject}
188+
setSelection={setSelection}
189+
status={placeholderObject}
101190
index={storyHash}
102191
storyId={story?.id}
103192
refId={DEFAULT_REF_ID}
@@ -108,23 +197,15 @@ export const Layout = ({
108197
)}
109198
</View>
110199

111-
<View style={{ flex: 1 }}>
112-
<View style={{ flex: 1, overflow: 'hidden' }}>{children}</View>
113-
114-
<View
115-
style={{
116-
height: desktopAddonsPanelOpen ? 300 : undefined,
117-
borderTopWidth: 1,
118-
borderColor: theme.appBorderColor,
119-
paddingTop: desktopAddonsPanelOpen ? 4 : 0,
120-
padding: desktopAddonsPanelOpen ? 0 : 10,
121-
}}
122-
>
200+
<View style={desktopContentContainerStyle}>
201+
<View style={desktopContentStyle}>{children}</View>
202+
203+
<View style={desktopAddonsPanelStyle}>
123204
{desktopAddonsPanelOpen ? (
124205
<AddonsTabs storyId={story?.id} onClose={() => setDesktopAddonsPanelOpen(false)} />
125206
) : (
126207
<IconButton
127-
style={{ marginLeft: 'auto' }}
208+
style={iconFloatRightStyle}
128209
onPress={() => setDesktopAddonsPanelOpen(true)}
129210
Icon={BottomBarToggleIcon}
130211
/>
@@ -136,28 +217,13 @@ export const Layout = ({
136217
}
137218

138219
return (
139-
<View
140-
style={{
141-
flex: 1,
142-
paddingTop: story?.parameters?.noSafeArea ? 0 : insets.top,
143-
backgroundColor: theme.background.content,
144-
}}
145-
>
146-
<View style={{ flex: 1, overflow: 'hidden' }}>
220+
<View style={mobileContainerStyle}>
221+
<View style={mobileContentStyle}>
147222
{children}
148223

149224
{story?.parameters?.hideFullScreenButton ? null : (
150225
<TouchableOpacity
151-
style={{
152-
position: 'absolute',
153-
bottom: uiHidden ? 56 + insets.bottom : 16,
154-
right: 16,
155-
backgroundColor: theme.background.content,
156-
padding: 4,
157-
borderRadius: 4,
158-
borderWidth: 1,
159-
borderColor: theme.appBorderColor,
160-
}}
226+
style={fullScreenButtonStyle}
161227
onPress={() => setUiHidden((prev) => !prev)}
162228
>
163229
{uiHidden ? (
@@ -170,18 +236,16 @@ export const Layout = ({
170236
</View>
171237

172238
{!uiHidden ? (
173-
<Container style={{ marginBottom: insets.bottom }}>
239+
<Container style={containerStyle}>
174240
<Nav>
175241
<Button
176242
testID="mobile-menu-button"
177-
style={{ flexShrink: 1 }}
178-
hitSlop={{ bottom: 10, left: 10, right: 10, top: 10 }}
179-
onPress={() => {
180-
mobileMenuDrawerRef.current.setMobileMenuOpen(true);
181-
}}
243+
style={navButtonStyle}
244+
hitSlop={navButtonHitSlop}
245+
onPress={openMobileMenu}
182246
>
183247
<MenuIcon color={theme.color.mediumdark} />
184-
<Text style={{ flexShrink: 1, color: theme.color.defaultText }} numberOfLines={1}>
248+
<Text style={navButtonTextStyle} numberOfLines={1}>
185249
{story?.title}/{story?.name}
186250
</Text>
187251
</Button>
@@ -196,21 +260,17 @@ export const Layout = ({
196260
) : null}
197261

198262
<MobileMenuDrawer ref={mobileMenuDrawerRef}>
199-
<View style={{ paddingLeft: 16, paddingTop: 4, paddingBottom: 4 }}>
263+
<View style={mobileMenuDrawerContentStyle}>
200264
<StorybookLogo theme={theme} />
201265
</View>
202266

203267
<Sidebar
204-
extra={[]}
268+
extra={placeholderArray}
205269
previewInitialized
206270
indexError={undefined}
207-
refs={{}}
208-
setSelection={({ storyId: newStoryId }) => {
209-
const channel = addons.getChannel();
210-
211-
channel.emit(SET_CURRENT_STORY, { storyId: newStoryId });
212-
}}
213-
status={{}}
271+
refs={placeholderObject}
272+
setSelection={setSelection}
273+
status={placeholderObject}
214274
index={storyHash}
215275
storyId={story?.id}
216276
refId={DEFAULT_REF_ID}

0 commit comments

Comments
 (0)