Skip to content

Commit b60d44d

Browse files
huntiefacebook-github-bot
authored andcommitted
Redesign New App Screen and move to package (#50939)
Summary: Pull Request resolved: #50939 Redesigns React Native's `NewAppScreen` component, and moves it into a new `react-native/new-app-screen` package with a single component export. Deletes the old New App Screen under `'react-native/Libraries/NewAppScreen/'`. {F1977434404} **Motivation** - **Reduces our public API** (see react-native-community/discussions-and-proposals#894) - Separates this screen from the main `react-native` package, where it was a number of subpath exports. - Reduces the size of the main `react-native` package, including image assets — which are redundant for consumers like Expo. - **Updated visual treatment** - Replace outdated logo, update to a responsive tablet/windowed layout. - Removes outdated guidance (e.g. "use cmd+R to reload"), and generally simplifies the layout (with the aim of reducing future maintenance). - **Simplifies template boilerplate** - `NewAppScreen` is now a fully encapsulated screen layout, avoiding the cruft of the previous modular design. **Integration plan** When we cut the `0.80-stable` branch, we'll update [the template](https://github.com/react-native-community/template/blob/main/template/App.tsx) to import and use `<NewAppScreen />`. - This will cause an extra runtime dependency in the template `package.json`, which will require user cleanup. We are happy with this tradeoff, given the self-evident package name, reduction of template boilerplate, and size reduction on the main `react-native` package. Changelog: [General][Breaking] - The `NewAppScreen` component is redesigned and moved to the `react-native/new-app-screen` package Differential Revision: D73657878
1 parent 8b0635b commit b60d44d

File tree

24 files changed

+442
-611
lines changed

24 files changed

+442
-611
lines changed

packages/helloworld/App.jsx

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7+
* @flow strict-local
78
* @format
89
*/
910

10-
import React from 'react';
11+
import * as React from 'react';
1112
import {
1213
SafeAreaView,
1314
ScrollView,
@@ -17,29 +18,15 @@ import {
1718
View,
1819
useColorScheme,
1920
} from 'react-native';
20-
import {Colors, Header} from 'react-native/Libraries/NewAppScreen';
2121

22-
function App(): React.JSX.Element {
22+
function App(): React.Node {
2323
const isDarkMode = useColorScheme() === 'dark';
2424

25-
const backgroundStyle = {
26-
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
27-
};
28-
2925
return (
30-
<SafeAreaView style={backgroundStyle}>
31-
<StatusBar
32-
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
33-
backgroundColor={backgroundStyle.backgroundColor}
34-
/>
35-
<ScrollView
36-
contentInsetAdjustmentBehavior="automatic"
37-
style={backgroundStyle}>
38-
<Header />
39-
<View
40-
style={{
41-
backgroundColor: isDarkMode ? Colors.black : Colors.white,
42-
}}>
26+
<SafeAreaView>
27+
<StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
28+
<ScrollView contentInsetAdjustmentBehavior="automatic">
29+
<View>
4330
<Text style={styles.title}>Hello, World!</Text>
4431
</View>
4532
</ScrollView>

packages/new-app-screen/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# @react-native/new-app-screen
2+
3+
![npm package](https://img.shields.io/npm/v/@react-native/new-app-screen?color=brightgreen&label=npm%20package)
4+
5+
`NewAppScreen` component for React Native.
6+
7+
## Usage
8+
9+
```js
10+
import { NewAppScreen } from '@react-native/new-app-screen';
11+
12+
function MyAppOrTemplate() {
13+
...
14+
15+
return <NewAppScreen />;
16+
}
17+
```
18+
19+
## Contributing
20+
21+
Changes to this package can be made locally and tested against the `rn-tester` app, per the [Contributing guide](https://reactnative.dev/contributing/overview#contributing-code).

packages/new-app-screen/package.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"name": "@react-native/new-app-screen",
3+
"version": "0.80.0-main",
4+
"description": "NewAppScreen component for React Native",
5+
"keywords": [
6+
"react-native"
7+
],
8+
"homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/new-app-screen#readme",
9+
"bugs": "https://github.com/facebook/react-native/issues",
10+
"repository": {
11+
"type": "git",
12+
"url": "git+https://github.com/facebook/react-native.git",
13+
"directory": "packages/new-app-screen"
14+
},
15+
"license": "MIT",
16+
"exports": "./src/index.js",
17+
"files": [
18+
"src"
19+
],
20+
"dependencies": {},
21+
"peerDependencies": {
22+
"@types/react": "^19.0.0",
23+
"react": "*",
24+
"react-native": "*"
25+
},
26+
"peerDependenciesMeta": {
27+
"@types/react": {
28+
"optional": true
29+
}
30+
},
31+
"engines": {
32+
"node": ">=18"
33+
}
34+
}

packages/new-app-screen/src/Links.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict-local
8+
* @format
9+
*/
10+
11+
const Links: Array<{
12+
title: string,
13+
description: string,
14+
url: string,
15+
}> = [
16+
{
17+
title: 'Hello World',
18+
description: 'Learn the basics',
19+
url: 'https://reactnative.dev/docs/tutorial',
20+
},
21+
{
22+
title: 'Fast Refresh',
23+
description: 'See edits instantly',
24+
url: 'https://reactnative.dev/docs/fast-refresh',
25+
},
26+
{
27+
title: 'DevTools',
28+
description: 'View logs & debug your app',
29+
url: 'https://reactnative.dev/docs/debugging',
30+
},
31+
{
32+
title: 'Components',
33+
description: 'View components and APIs',
34+
url: 'https://reactnative.dev/docs/components-and-apis',
35+
},
36+
{
37+
title: 'Style',
38+
description: 'Use the style prop',
39+
url: 'https://reactnative.dev/docs/style',
40+
},
41+
{
42+
title: 'Layout',
43+
description: 'Flexbox & layout techniques',
44+
url: 'https://reactnative.dev/docs/flexbox',
45+
},
46+
{
47+
title: 'Navigation',
48+
description: 'Move between screens',
49+
url: 'https://reactnative.dev/docs/navigation',
50+
},
51+
{
52+
title: 'Networking',
53+
description: 'Use the Fetch API',
54+
url: 'https://reactnative.dev/docs/navigation',
55+
},
56+
{
57+
title: 'Showcase',
58+
description: 'Featured React Native apps',
59+
url: 'https://reactnative.dev/showcase',
60+
},
61+
{
62+
title: 'Blog',
63+
description: 'Latest news & updates',
64+
url: 'https://reactnative.dev/blog',
65+
},
66+
{
67+
title: 'Community',
68+
description: 'Expore & get help',
69+
url: 'https://reactnative.dev/community/overview',
70+
},
71+
{
72+
title: 'Follow @reactnative',
73+
description: 'Stay in touch on X',
74+
url: 'https://x.com/reactnative',
75+
},
76+
];
77+
78+
export default Links;
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict-local
8+
* @format
9+
*/
10+
11+
import Links from './Links';
12+
import {ThemedText, useTheme} from './Theme';
13+
import * as React from 'react';
14+
import {
15+
Image,
16+
SafeAreaView,
17+
ScrollView,
18+
StyleSheet,
19+
Text,
20+
TouchableHighlight,
21+
View,
22+
useColorScheme,
23+
useWindowDimensions,
24+
} from 'react-native';
25+
import openURLInBrowser from 'react-native/Libraries/Core/Devtools/openURLInBrowser';
26+
import {version as ReactNativeVersion} from 'react-native/Libraries/Core/ReactNativeVersion';
27+
28+
export type NewAppScreenProps = $ReadOnly<{
29+
templateFileName?: string,
30+
}>;
31+
32+
export default function NewAppScreen({
33+
templateFileName = 'App.tsx',
34+
}: NewAppScreenProps): React.Node {
35+
const {colors} = useTheme();
36+
const isDarkMode = useColorScheme() === 'dark';
37+
const isLargeScreen = useWindowDimensions().width > 600;
38+
39+
return (
40+
<SafeAreaView style={{backgroundColor: colors.background}}>
41+
<ScrollView>
42+
<View style={styles.container}>
43+
<View style={styles.header}>
44+
<Image
45+
style={styles.logo}
46+
source={
47+
isDarkMode
48+
? require('./assets/react-dark.png')
49+
: require('./assets/react-light.png')
50+
}
51+
/>
52+
<ThemedText style={styles.title}>
53+
Welcome to React Native
54+
</ThemedText>
55+
{getVersionLabel()}
56+
{getHermesLabel()}
57+
<ThemedText
58+
style={[
59+
styles.callout,
60+
{backgroundColor: colors.backgroundHighlight},
61+
]}>
62+
💡&ensp;Open{' '}
63+
<Text style={styles.calloutEmphasis}>{templateFileName}</Text> to
64+
get started
65+
</ThemedText>
66+
</View>
67+
<View style={styles.linksContainer}>
68+
<ThemedText style={styles.linksTitle}>Learn & Explore</ThemedText>
69+
{Links.map(({title, description, url}, i) => (
70+
<TouchableHighlight
71+
key={i}
72+
activeOpacity={0.6}
73+
underlayColor={colors.background}
74+
onPress={() => openURLInBrowser(url)}
75+
style={[
76+
styles.link,
77+
// eslint-disable-next-line react-native/no-inline-styles
78+
{
79+
maxWidth: isLargeScreen ? 240 : 360,
80+
borderColor: colors.cardOutline,
81+
backgroundColor: colors.cardBackground,
82+
},
83+
]}>
84+
<View>
85+
<ThemedText style={styles.linkText}>{title}</ThemedText>
86+
<ThemedText style={{color: colors.textSecondary}}>
87+
{description}
88+
</ThemedText>
89+
</View>
90+
</TouchableHighlight>
91+
))}
92+
</View>
93+
</View>
94+
</ScrollView>
95+
</SafeAreaView>
96+
);
97+
}
98+
99+
function getVersionLabel(): React.Node {
100+
const version =
101+
[
102+
ReactNativeVersion.major,
103+
ReactNativeVersion.minor,
104+
ReactNativeVersion.patch,
105+
].join('.') +
106+
(ReactNativeVersion.prerelease != null
107+
? '-' + ReactNativeVersion.prerelease
108+
: '');
109+
110+
return (
111+
<ThemedText color="secondary" style={styles.label}>
112+
Version: {version}
113+
</ThemedText>
114+
);
115+
}
116+
117+
function getHermesLabel(): React.Node {
118+
if (global.HermesInternal == null) {
119+
return null;
120+
}
121+
122+
return (
123+
<ThemedText color="secondary" style={styles.label}>
124+
JS Engine: Hermes
125+
</ThemedText>
126+
);
127+
}
128+
129+
const styles = StyleSheet.create({
130+
container: {
131+
flexGrow: 1,
132+
alignItems: 'center',
133+
paddingHorizontal: 24,
134+
},
135+
header: {
136+
width: '100%',
137+
alignItems: 'center',
138+
marginTop: 64,
139+
marginBottom: 48,
140+
},
141+
logo: {
142+
height: 80,
143+
aspectRatio: 1,
144+
marginBottom: 24,
145+
},
146+
title: {
147+
fontSize: 24,
148+
fontWeight: '600',
149+
marginBottom: 24,
150+
},
151+
label: {
152+
fontSize: 14,
153+
marginBottom: 8,
154+
},
155+
callout: {
156+
width: '100%',
157+
maxWidth: 320,
158+
marginTop: 36,
159+
paddingVertical: 16,
160+
paddingHorizontal: 20,
161+
paddingLeft: 16,
162+
borderRadius: 12,
163+
fontSize: 16,
164+
textAlign: 'center',
165+
},
166+
calloutEmphasis: {
167+
fontWeight: 'bold',
168+
},
169+
linksContainer: {
170+
flex: 1,
171+
flexWrap: 'wrap',
172+
flexDirection: 'row',
173+
justifyContent: 'center',
174+
columnGap: 12,
175+
rowGap: 12,
176+
maxWidth: 800,
177+
marginBottom: 48,
178+
},
179+
linksTitle: {
180+
width: '100%',
181+
fontSize: 18,
182+
fontWeight: '600',
183+
textAlign: 'center',
184+
marginBottom: 20,
185+
},
186+
link: {
187+
width: '100%',
188+
paddingVertical: 20,
189+
paddingHorizontal: 24,
190+
borderRadius: 12,
191+
borderWidth: 1,
192+
boxShadow: '0 4px 8px rgba(0, 0, 0, .03)',
193+
},
194+
linkText: {
195+
marginBottom: 4,
196+
fontSize: 16,
197+
fontWeight: '600',
198+
},
199+
});

0 commit comments

Comments
 (0)