From 08c09d915dc6f6579446913a51994eb1898ed88d Mon Sep 17 00:00:00 2001 From: theblondealex Date: Tue, 5 Nov 2024 19:24:53 +0000 Subject: [PATCH] Added Zustand and state management option --- .changeset/twenty-chefs-burn.md | 9 +++++++ cli/src/commands/create-expo-stack.ts | 24 +++++++++++++++-- cli/src/templates/base/package.json.ejs | 4 +++ .../packages/zustand/store/store.ts.ejs | 15 +++++++++++ cli/src/types.ts | 5 +++- cli/src/utilities/configureProjectFiles.ts | 9 ++++++- cli/src/utilities/generateProjectFiles.ts | 11 ++++++-- cli/src/utilities/runCLI.ts | 27 +++++++++++++++++++ docs/src/content/docs/en/installation.md | 1 + 9 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 .changeset/twenty-chefs-burn.md create mode 100644 cli/src/templates/packages/zustand/store/store.ts.ejs diff --git a/.changeset/twenty-chefs-burn.md b/.changeset/twenty-chefs-burn.md new file mode 100644 index 00000000..ce2419c6 --- /dev/null +++ b/.changeset/twenty-chefs-burn.md @@ -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 diff --git a/cli/src/commands/create-expo-stack.ts b/cli/src/commands/create-expo-stack.ts index 16e14522..37851f80 100644 --- a/cli/src/commands/create-expo-stack.ts +++ b/cli/src/commands/create-expo-stack.ts @@ -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({ @@ -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) => { @@ -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( @@ -418,7 +436,8 @@ const command: GluegunCommand = { analyticsPackage, toolbox, cliResults, - internalizationPackage + internalizationPackage, + stateManagementPackage ); // Once all the files are defined, format and generate them @@ -434,7 +453,8 @@ const command: GluegunCommand = { packageManager, stylingPackage, toolbox, - internalizationPackage + internalizationPackage, + stateManagementPackage ); await printOutput(cliResults, formattedFiles, toolbox, stylingPackage); diff --git a/cli/src/templates/base/package.json.ejs b/cli/src/templates/base/package.json.ejs index e06d180e..5822640c 100644 --- a/cli/src/templates/base/package.json.ejs +++ b/cli/src/templates/base/package.json.ejs @@ -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", diff --git a/cli/src/templates/packages/zustand/store/store.ts.ejs b/cli/src/templates/packages/zustand/store/store.ts.ejs new file mode 100644 index 00000000..e37da7fa --- /dev/null +++ b/cli/src/templates/packages/zustand/store/store.ts.ejs @@ -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((set) => ({ + bears: 0, + increasePopulation: () => set((state) => ({ bears: state.bears + 1 })), + removeAllBears: () => set({ bears: 0 }), + updateBears: (newBears) => set({ bears: newBears }), +})) \ No newline at end of file diff --git a/cli/src/types.ts b/cli/src/types.ts index 48931900..ef0b22c9 100644 --- a/cli/src/types.ts +++ b/cli/src/types.ts @@ -26,6 +26,7 @@ export const availablePackages = [ 'restyle', 'unistyles', 'i18next', + 'zustand', 'vexo-analytics' ] as const; @@ -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'; @@ -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 }; }; diff --git a/cli/src/utilities/configureProjectFiles.ts b/cli/src/utilities/configureProjectFiles.ts index 9f130d99..0e5a216e 100644 --- a/cli/src/utilities/configureProjectFiles.ts +++ b/cli/src/utilities/configureProjectFiles.ts @@ -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 = [ @@ -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'); diff --git a/cli/src/utilities/generateProjectFiles.ts b/cli/src/utilities/generateProjectFiles.ts index 15dd1ad5..431e841b 100644 --- a/cli/src/utilities/generateProjectFiles.ts +++ b/cli/src/utilities/generateProjectFiles.ts @@ -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; @@ -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') { @@ -79,7 +85,8 @@ export function generateProjectFiles( packageManager, packages, stylingPackage, - internalizationPackage + internalizationPackage, + stateManagementPackage } }); diff --git a/cli/src/utilities/runCLI.ts b/cli/src/utilities/runCLI.ts index 6a7c6553..810d76f5 100644 --- a/cli/src/utilities/runCLI.ts +++ b/cli/src/utilities/runCLI.ts @@ -5,6 +5,7 @@ import { semver } from 'gluegun'; import { bunInstallationError, defaultOptions, nativeWindUIOptions } from '../constants'; import { AuthenticationSelect, + StateManagementSelect, CliResults, NavigationSelect, NavigationTypes, @@ -327,6 +328,32 @@ export async function runCLI(toolbox: Toolbox, projectName: string): Promise