Skip to content

Commit 8bea1f9

Browse files
authored
feat(cli): expo-router option (#2727 by @frankcalise)
* feat(cli): experimental expo-router flag * chore: todo notes for expo router screen gen * fix(cli): always do expo install --fix check * fix(cli): prompt about expo-router, fix exp flags output in buildCliCommand * fix(expo-router): mst directives for template file * fix(cli): updates for mst markup * fix(cli): remove-mst src dir param * fix(cli): update generators for expo-router and obey --mst * fix(cli): clean up cmd with helpers * docs: update cli docs for expo router flag * fix(cli): remove unnecessary file patch for router conversion * test(cli): add expo router tests * fix(cli): router prompt grammar, tone down experimental barking * fix(cli): reworks --mst to --state=mst (#2731 by @frankcalise) * fix(cli): reworks --mst to --state=mst * refactor(cli): tidy up MST removal
1 parent dff3d24 commit 8bea1f9

File tree

12 files changed

+563
-71
lines changed

12 files changed

+563
-71
lines changed

boilerplate/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ buck-out/
7171
bin/Exponent.app
7272
/android
7373
/ios
74+
expo-env.d.ts
7475

7576
## Secrets
7677
npm-debug.*

boilerplate/app/components/ListItem.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ interface ListItemActionProps {
104104
* @param {ListItemProps} props - The props for the `ListItem` component.
105105
* @returns {JSX.Element} The rendered `ListItem` component.
106106
*/
107-
export function ListItem(props: ListItemProps) {
107+
export const ListItem = React.forwardRef<View, ListItemProps>(function ListItem(
108+
props: ListItemProps,
109+
ref,
110+
) {
108111
const {
109112
bottomSeparator,
110113
children,
@@ -138,7 +141,7 @@ export function ListItem(props: ListItemProps) {
138141
const $touchableStyles = [$styles.row, $touchableStyle, { minHeight: height }, style]
139142

140143
return (
141-
<View style={themed($containerStyles)}>
144+
<View ref={ref} style={themed($containerStyles)}>
142145
<TouchableOpacity {...TouchableOpacityProps} style={$touchableStyles}>
143146
<ListItemAction
144147
side="left"
@@ -162,7 +165,7 @@ export function ListItem(props: ListItemProps) {
162165
</TouchableOpacity>
163166
</View>
164167
)
165-
}
168+
})
166169

167170
/**
168171
* @param {ListItemActionProps} props - The props for the `ListItemAction` component.

boilerplate/src/app/_layout.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from "react"
2+
import { ViewStyle } from "react-native"
3+
import { Slot, SplashScreen } from "expo-router"
4+
import { GestureHandlerRootView } from "react-native-gesture-handler"
5+
// @mst replace-next-line
6+
import { useInitialRootStore } from "src/models"
7+
import { useFonts } from "@expo-google-fonts/space-grotesk"
8+
import { customFontsToLoad } from "src/theme"
9+
10+
SplashScreen.preventAutoHideAsync()
11+
12+
if (__DEV__) {
13+
// Load Reactotron configuration in development. We don't want to
14+
// include this in our production bundle, so we are using `if (__DEV__)`
15+
// to only execute this in development.
16+
require("src/devtools/ReactotronConfig.ts")
17+
}
18+
19+
export { ErrorBoundary } from "src/components/ErrorBoundary/ErrorBoundary"
20+
21+
export default function Root() {
22+
// @mst remove-block-start
23+
// Wait for stores to load and render our layout inside of it so we have access
24+
// to auth info etc
25+
const { rehydrated } = useInitialRootStore()
26+
// @mst remove-block-end
27+
28+
const [fontsLoaded, fontError] = useFonts(customFontsToLoad)
29+
30+
const loaded = fontsLoaded && rehydrated
31+
32+
React.useEffect(() => {
33+
if (fontError) throw fontError
34+
}, [fontError])
35+
36+
React.useEffect(() => {
37+
if (loaded) {
38+
SplashScreen.hideAsync()
39+
}
40+
}, [loaded])
41+
42+
if (!loaded) {
43+
return null
44+
}
45+
46+
return <GestureHandlerRootView style={$root}><Slot /></GestureHandlerRootView>
47+
}
48+
49+
const $root: ViewStyle = { flex: 1 }

boilerplate/src/app/index.tsx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// @mst replace-next-line
2+
import { observer } from "mobx-react-lite"
3+
import React from "react"
4+
import { Image, ImageStyle, TextStyle, View, ViewStyle } from "react-native"
5+
import { Text } from "src/components"
6+
import { isRTL } from "../i18n"
7+
import { colors, spacing } from "../theme"
8+
import { useSafeAreaInsetsStyle } from "../utils/useSafeAreaInsetsStyle"
9+
10+
const welcomeLogo = require("../../assets/images/logo.png")
11+
const welcomeFace = require("../../assets/images/welcome-face.png")
12+
13+
// @mst replace-next-line export default function WelcomeScreen() {
14+
export default observer(function WelcomeScreen() {
15+
const $bottomContainerInsets = useSafeAreaInsetsStyle(["bottom"])
16+
17+
return (
18+
<View style={$container}>
19+
<View style={$topContainer}>
20+
<Image style={$welcomeLogo} source={welcomeLogo} resizeMode="contain" />
21+
<Text
22+
testID="welcome-heading"
23+
style={$welcomeHeading}
24+
tx="welcomeScreen.readyForLaunch"
25+
preset="heading"
26+
/>
27+
<Text tx="welcomeScreen.exciting" preset="subheading" />
28+
<Image style={$welcomeFace} source={welcomeFace} resizeMode="contain" />
29+
</View>
30+
31+
<View style={[$bottomContainer, $bottomContainerInsets]}>
32+
<Text tx="welcomeScreen.postscript" size="md" />
33+
</View>
34+
</View>
35+
)
36+
// @mst replace-next-line }
37+
})
38+
39+
const $container: ViewStyle = {
40+
flex: 1,
41+
backgroundColor: colors.background,
42+
}
43+
44+
const $topContainer: ViewStyle = {
45+
flexShrink: 1,
46+
flexGrow: 1,
47+
flexBasis: "57%",
48+
justifyContent: "center",
49+
paddingHorizontal: spacing.lg,
50+
}
51+
52+
const $bottomContainer: ViewStyle = {
53+
flexShrink: 1,
54+
flexGrow: 0,
55+
flexBasis: "43%",
56+
backgroundColor: colors.palette.neutral100,
57+
borderTopLeftRadius: 16,
58+
borderTopRightRadius: 16,
59+
paddingHorizontal: spacing.lg,
60+
justifyContent: "space-around",
61+
}
62+
const $welcomeLogo: ImageStyle = {
63+
height: 88,
64+
width: "100%",
65+
marginBottom: spacing.xxl,
66+
}
67+
68+
const $welcomeFace: ImageStyle = {
69+
height: 169,
70+
width: 269,
71+
position: "absolute",
72+
bottom: -47,
73+
right: -80,
74+
transform: [{ scaleX: isRTL ? -1 : 1 }],
75+
}
76+
77+
const $welcomeHeading: TextStyle = {
78+
marginBottom: spacing.md,
79+
}

boilerplate/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@
3232
"module": "commonjs"
3333
}
3434
},
35-
"include": ["index.js", "App.tsx", "app", "types", "plugins", "app.config.ts"],
35+
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"],
3636
"exclude": ["node_modules", "test/**/*"]
3737
}

docs/cli/Ignite-CLI.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,13 @@ Starts the interactive prompt for generating a new Ignite project. Any options n
9898
- `--overwrite` overwrite the target directory if it exists
9999
- `--targetPath` string, specify a target directory where the project should be created
100100
- `--removeDemo` will remove the boilerplate demo code after project creation
101-
- `--mst` flag to specify whether to include MobX-State-Tree in project (can only be set to `false` if `--removeDemo=true`)
101+
- `--state` string, one of `mst` or `none` to include MobX-State-Tree in project (can only be set to `none` if `--removeDemo=true`)
102102
- `--useCache` flag specifying to use dependency cache for quicker installs
103103
- `--no-timeout` flag to disable the timeout protection (useful for slow internet connections)
104104
- `--yes` accept all prompt defaults
105-
- `--workflow` string, one of `expo`, `cng` or `manual` for project initialization
105+
- `--workflow` string, one of `cng` or `manual` for project initialization
106106
- `--experimental` comma separated string, indicates experimental features (which may or may not be stable) to turn on during installation. **A CNG workflow is require for these flags** `--workflow=cng`
107+
- `expo-router` converts the project to [Expo Router](https://docs.expo.dev/router/introduction/) from React Navigation
107108
- `new-arch` enables [The New Architecture](https://reactnative.dev/docs/new-architecture-intro)
108109
- `expo-canary` uses Expo's highly experimental canary release instead of the la test stable SDK
109110
- `expo-beta` uses Expo's latest beta SDK available instead of the latest stable SDK

docs/concept/MobX-State-Tree.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ We also recognize no state management solution is perfect. MST has some known do
4141

4242
### Remove MST Option
4343

44-
We understand that state management is a highly opinionated topic with various options available. To accommodate this, we've added an option in Ignite CLI to remove MobX-State-Tree if you choose so! When Igniting a new project, provide `--mst=false` to remove MobX-State-Tree code from the boilerplate. This option only works when also removing demo code.
44+
We understand that state management is a highly opinionated topic with various options available. To accommodate this, we've added an option in Ignite CLI to remove MobX-State-Tree if you choose so! When Igniting a new project, provide `--state=none` to remove MobX-State-Tree code from the boilerplate. This option only works when also removing demo code.
4545

4646
```
47-
npx ignite-cli@latest new PizzaApp --removeDemo=true --mst=false
47+
npx ignite-cli@latest new PizzaApp --removeDemo=true --state=none
4848
```
4949

5050
## Learning MobX-State-Tree

0 commit comments

Comments
 (0)