Skip to content

Commit

Permalink
Added Zustand and state management option
Browse files Browse the repository at this point in the history
  • Loading branch information
theblondealex authored and dannyhw committed Nov 6, 2024
1 parent 8f6977e commit 08c09d9
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 6 deletions.
9 changes: 9 additions & 0 deletions .changeset/twenty-chefs-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'create-expo-stack': minor
---

Added a StateManagement Question with zustand to start and potentially more to follow

- setup with a question prompt just before the internationalization prompt
- --zustand flag to skip the prompt
- Adds a StateManagement folder to the project with a zustandStore.ts file to start with
24 changes: 22 additions & 2 deletions cli/src/commands/create-expo-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,15 @@ const command: GluegunCommand = {
});
}

// State Management packages
if (options.zustand) {
// Add zustand package
cliResults.packages.push({
name: 'zustand',
type: 'state-management'
});
}

// Internalization packages
if (options.i18next) {
cliResults.packages.push({
Expand Down Expand Up @@ -354,6 +363,12 @@ const command: GluegunCommand = {
script += '--drawer+tabs ';
}
}

const stateManagementPackage = cliResults.packages.find((p) => p.type === 'state-management');

if (stateManagementPackage) {
script += `--${stateManagementPackage.name} `;
}
} else {
// Add the packages
cliResults.packages.forEach((p) => {
Expand Down Expand Up @@ -408,6 +423,9 @@ const command: GluegunCommand = {
const internalizationPackage = packages.find((p) => p.type === 'internationalization');
const analyticsPackage = packages.find((p) => p.type === 'analytics');

//add the state management package if it is selected
const stateManagementPackage = packages.find((p) => p.type === 'state-management') || undefined;

let files: string[] = [];

files = configureProjectFiles(
Expand All @@ -418,7 +436,8 @@ const command: GluegunCommand = {
analyticsPackage,
toolbox,
cliResults,
internalizationPackage
internalizationPackage,
stateManagementPackage
);

// Once all the files are defined, format and generate them
Expand All @@ -434,7 +453,8 @@ const command: GluegunCommand = {
packageManager,
stylingPackage,
toolbox,
internalizationPackage
internalizationPackage,
stateManagementPackage
);

await printOutput(cliResults, formattedFiles, toolbox, stylingPackage);
Expand Down
4 changes: 4 additions & 0 deletions cli/src/templates/base/package.json.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
"@react-native-community/slider": "4.5.2",
<% } %>
<% } %>
<% if (props.stateManagementPackage?.name === "zustand") { %>
"zustand": "^4.5.1",
<% } %>
<% if (props.stylingPackage?.name === "restyle") { %>
"@shopify/restyle": "^2.4.2",
Expand Down
15 changes: 15 additions & 0 deletions cli/src/templates/packages/zustand/store/store.ts.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { create } from 'zustand'

export interface BearState {
bears: number
increasePopulation: () => void
removeAllBears: () => void
updateBears: (newBears: number) => void
}

export const useStore = create<BearState>((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
updateBears: (newBears) => set({ bears: newBears }),
}))
5 changes: 4 additions & 1 deletion cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const availablePackages = [
'restyle',
'unistyles',
'i18next',
'zustand',
'vexo-analytics'
] as const;

Expand All @@ -39,6 +40,8 @@ export type StylingSelect = 'nativewind' | 'restyle' | 'stylesheet' | 'tamagui'

export type PackageManager = 'yarn' | 'npm' | 'pnpm' | 'bun';

export type StateManagementSelect = 'zustand' | undefined;

export type Internalization = 'i18next';

export type Analytics = 'vexo-analytics';
Expand All @@ -59,7 +62,7 @@ export type SelectedComponents =

export type AvailablePackages = {
name: (typeof availablePackages)[number];
type: 'navigation' | 'styling' | 'authentication' | 'internationalization' | 'analytics';
type: 'navigation' | 'styling' | 'authentication' | 'internationalization' | 'state-management' | 'analytics';
options?: { selectedComponents?: SelectedComponents[]; type?: NavigationTypes };
};

Expand Down
9 changes: 8 additions & 1 deletion cli/src/utilities/configureProjectFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export function configureProjectFiles(
analyticsPackage: AvailablePackages | undefined,
toolbox: Toolbox,
cliResults: CliResults,
internalizationPackage: AvailablePackages | undefined
internalizationPackage: AvailablePackages | undefined,
stateManagementPackage: AvailablePackages | undefined
): string[] {
// Define the files common to all templates to be generated
let baseFiles = [
Expand Down Expand Up @@ -349,6 +350,12 @@ export function configureProjectFiles(
}
}

// add state management files if needed
if (stateManagementPackage?.name === 'zustand') {
const zustandFiles = ['packages/zustand/store/store.ts.ejs'];
files = [...files, ...zustandFiles];
}

// Add npmrc file if user is using pnpm
if (packageManager === 'pnpm') {
files.push('base/.npmrc.ejs');
Expand Down
11 changes: 9 additions & 2 deletions cli/src/utilities/generateProjectFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export function generateProjectFiles(
packageManager: PackageManager,
stylingPackage: AvailablePackages | undefined,
toolbox: Toolbox,
internalizationPackage: AvailablePackages | undefined
internalizationPackage: AvailablePackages | undefined,
stateManagementPackage: AvailablePackages | undefined
) {
const { projectName, packages, flags } = cliResults;

Expand All @@ -27,6 +28,11 @@ export function generateProjectFiles(
target = target.replace('packages/firebase/', '');
}

//state management
if (stateManagementPackage?.name === 'zustand') {
target = target.replace('packages/zustand/', '');
}

target = target.replace('base/', '');

if (stylingPackage?.name === 'tamagui') {
Expand Down Expand Up @@ -79,7 +85,8 @@ export function generateProjectFiles(
packageManager,
packages,
stylingPackage,
internalizationPackage
internalizationPackage,
stateManagementPackage
}
});

Expand Down
27 changes: 27 additions & 0 deletions cli/src/utilities/runCLI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { semver } from 'gluegun';
import { bunInstallationError, defaultOptions, nativeWindUIOptions } from '../constants';
import {
AuthenticationSelect,
StateManagementSelect,
CliResults,
NavigationSelect,
NavigationTypes,
Expand Down Expand Up @@ -327,6 +328,32 @@ export async function runCLI(toolbox: Toolbox, projectName: string): Promise<Cli
);
}

const stateManagementSelect = await select({
message: 'What would you like to use for state management?',
options: [
{ value: undefined, label: 'None' },
{ value: 'zustand', label: 'Zustand' }
// { value: 'mobx', label: 'MobX' },
// { value: 'redux', label: 'Redux' },
]
});

if (isCancel(stateManagementSelect)) {
cancel('Cancelled... 👋');
return process.exit(0);
}

if (stateManagementSelect) {
cliResults.packages.push({
name: stateManagementSelect as StateManagementSelect,
type: 'state-management'
});

success(`You'll be using ${stateManagementSelect} for state management.`);
} else {
success(`No problem, skipping state management for now.`);
}

const authenticationSelect = await select({
message: 'What would you like to use for authentication?',
options: [
Expand Down
1 change: 1 addition & 0 deletions docs/src/content/docs/en/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,6 @@ bun create expo-stack myapp --expo-router --nativewind --bun
| `--tamagui` | Use Tamagui for styling |
| `--restyle` | Use Restyle for styling |
| `--stylesheet` | Use StyleSheet for styling, used by default |
| `--zustand` | Use Zustand for state management |
| `--i18next` | Use i18next for internationalization |
| `-i`, `--ignite` | Initialize an opinionated starter using Infinite Red's Ignite |

0 comments on commit 08c09d9

Please sign in to comment.