├── .gitignore ├── base-projects ├── vite-base-js │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ └── main.jsx │ └── vite.config.js └── vite-base-ts │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── App.tsx │ ├── main.tsx │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── ch02 ├── dark-mode-dedicated │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ └── main.jsx │ └── vite.config.js ├── dark-mode-selector │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ └── main.jsx │ └── vite.config.js ├── dark-mode-typed │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── App.tsx │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── dark-mode │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ └── main.jsx │ └── vite.config.js ├── radio-complex │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── RadioGroup.jsx │ │ └── main.jsx │ └── vite.config.js ├── radio-composite │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── main.jsx │ │ └── radiogroup │ │ │ ├── Details.jsx │ │ │ ├── Option.jsx │ │ │ ├── RadioGroup.jsx │ │ │ ├── contexts.js │ │ │ └── index.js │ └── vite.config.js ├── radio-simple │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── RadioGroup.jsx │ │ └── main.jsx │ └── vite.config.js ├── radio-summary │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── main.jsx │ │ └── radiogroup │ │ │ ├── Details.jsx │ │ │ ├── Option.jsx │ │ │ ├── RadioGroup.jsx │ │ │ ├── contexts.js │ │ │ ├── index.js │ │ │ └── useContextValue.js │ └── vite.config.js ├── task-summary │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── CompactTaskManager.jsx │ │ ├── LongTaskManager.jsx │ │ ├── main.jsx │ │ ├── useNewTask.js │ │ └── useTaskList.js │ └── vite.config.js └── user-summary │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ ├── App.jsx │ ├── CompactUserProfile.jsx │ ├── LongUserProfile.jsx │ ├── UserDataForm.jsx │ ├── UserDetails.jsx │ ├── UserPreferences.jsx │ ├── main.jsx │ ├── useAPI.js │ └── useUserProfile.js │ └── vite.config.js ├── ch03 ├── employees │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ └── main.jsx │ └── vite.config.js ├── rerender │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── NoRerenderWithPropsChange.jsx │ │ ├── RerenderWithoutPropsChange.jsx │ │ ├── Rerenderable.jsx │ │ └── main.jsx │ └── vite.config.js ├── strict-mode │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ └── main.jsx │ └── vite.config.js ├── todo-delete │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ └── main.jsx │ └── vite.config.js ├── todo-fixed │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ └── main.jsx │ └── vite.config.js ├── todo-memo │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ └── main.jsx │ └── vite.config.js ├── todo-simple │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ └── main.jsx │ └── vite.config.js └── todo-usememo │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ ├── App.jsx │ └── main.jsx │ └── vite.config.js ├── ch04 ├── dark-mode │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ └── main.jsx │ └── vite.config.js └── prettier │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ ├── App.jsx │ └── main.jsx │ └── vite.config.js ├── ch05 ├── book-review │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── App.tsx │ │ ├── BookReview.css │ │ ├── BookReview.tsx │ │ ├── Rating.css │ │ ├── Rating.tsx │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── employee │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── App.tsx │ │ ├── EmployeeCard.tsx │ │ ├── app.css │ │ ├── employee.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── employees │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── App.tsx │ │ ├── EmployeeCard.tsx │ │ ├── app.css │ │ ├── employee.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts └── product-card │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── App.css │ ├── App.tsx │ ├── ProductCard.css │ ├── ProductCard.tsx │ ├── index.css │ ├── main.tsx │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── ch06 ├── appointment │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── App.tsx │ │ ├── AppointmentResponse.tsx │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── dark-mode │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── App.tsx │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── paginable │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── App.tsx │ │ ├── EmployeeCard.tsx │ │ ├── HighscoreEntry.tsx │ │ ├── Paginable.tsx │ │ ├── app.css │ │ ├── employee.css │ │ ├── highscore.css │ │ ├── main.tsx │ │ ├── paginable.css │ │ ├── types.ts │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── playlist │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── App.tsx │ │ ├── Playlist.tsx │ │ ├── PlaylistItem.tsx │ │ ├── main.tsx │ │ ├── playlist.css │ │ ├── types.ts │ │ ├── useReorderable.ts │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── tag-form │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── App.tsx │ │ ├── TagForm.tsx │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts └── use-reorderable │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── App.tsx │ ├── Playlist.tsx │ ├── main.tsx │ ├── playlist.css │ ├── useReorderable.ts │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── ch07 ├── classnames │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── Button.jsx │ │ ├── app.css │ │ ├── button.css │ │ └── main.jsx │ └── vite.config.js ├── cssmodules │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── Button.jsx │ │ ├── app.module.css │ │ ├── button.module.css │ │ └── main.jsx │ └── vite.config.js ├── inline │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── Button.jsx │ │ └── main.jsx │ └── vite.config.js ├── styled │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── Button.jsx │ │ └── main.jsx │ └── vite.config.js └── tailwind │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── postcss.config.js │ ├── src │ ├── App.jsx │ ├── Button.jsx │ ├── index.css │ └── main.jsx │ ├── tailwind.config.js │ └── vite.config.js ├── ch08 ├── context │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── data │ │ │ ├── DataContext.js │ │ │ ├── DataProvider.jsx │ │ │ ├── index.js │ │ │ ├── useAddThing.js │ │ │ ├── useAllThings.js │ │ │ ├── useCurrentThing.js │ │ │ ├── useData.js │ │ │ └── useThing.js │ │ ├── main.jsx │ │ └── things │ │ │ ├── AddAThing.jsx │ │ │ ├── AllThings.jsx │ │ │ ├── Button.jsx │ │ │ ├── Grid.jsx │ │ │ ├── Progress.jsx │ │ │ ├── RemoveButton.jsx │ │ │ ├── SingleThing.jsx │ │ │ ├── Thing.jsx │ │ │ ├── ThingTitle.jsx │ │ │ ├── Things.jsx │ │ │ └── index.js │ └── vite.config.js ├── reducer │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── data │ │ │ ├── DataContext.js │ │ │ ├── DataProvider.jsx │ │ │ ├── index.js │ │ │ ├── useAddThing.js │ │ │ ├── useAllThings.js │ │ │ ├── useCurrentThing.js │ │ │ ├── useData.js │ │ │ └── useThing.js │ │ ├── main.jsx │ │ └── things │ │ │ ├── AddAThing.jsx │ │ │ ├── AllThings.jsx │ │ │ ├── Button.jsx │ │ │ ├── Grid.jsx │ │ │ ├── Progress.jsx │ │ │ ├── RemoveButton.jsx │ │ │ ├── SingleThing.jsx │ │ │ ├── Thing.jsx │ │ │ ├── ThingTitle.jsx │ │ │ ├── Things.jsx │ │ │ └── index.js │ └── vite.config.js ├── redux │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── data │ │ │ ├── DataProvider.jsx │ │ │ ├── index.js │ │ │ ├── store.js │ │ │ ├── useAddThing.js │ │ │ ├── useAllThings.js │ │ │ ├── useCurrentThing.js │ │ │ ├── useData.js │ │ │ └── useThing.js │ │ ├── main.jsx │ │ └── things │ │ │ ├── AddAThing.jsx │ │ │ ├── AllThings.jsx │ │ │ ├── Button.jsx │ │ │ ├── Grid.jsx │ │ │ ├── Progress.jsx │ │ │ ├── RemoveButton.jsx │ │ │ ├── SingleThing.jsx │ │ │ ├── Thing.jsx │ │ │ ├── ThingTitle.jsx │ │ │ ├── Things.jsx │ │ │ └── index.js │ └── vite.config.js ├── xstate │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── data │ │ │ ├── DataContext.js │ │ │ ├── DataProvider.jsx │ │ │ ├── actions.js │ │ │ ├── index.js │ │ │ ├── machine.js │ │ │ ├── useAddThing.js │ │ │ ├── useAllThings.js │ │ │ ├── useCurrentThing.js │ │ │ ├── useData.js │ │ │ ├── useSend.js │ │ │ ├── useThatThing.js │ │ │ └── useThisThing.js │ │ ├── main.jsx │ │ └── things │ │ │ ├── AddAThing.jsx │ │ │ ├── AllThings.jsx │ │ │ ├── Button.jsx │ │ │ ├── Grid.jsx │ │ │ ├── Progress.jsx │ │ │ ├── RemoveButton.jsx │ │ │ ├── SingleThing.jsx │ │ │ ├── Thing.jsx │ │ │ ├── ThingTitle.jsx │ │ │ ├── Things.jsx │ │ │ └── index.js │ └── vite.config.js └── zustand │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ ├── App.jsx │ ├── data │ │ ├── DataProvider.jsx │ │ ├── index.js │ │ ├── useAddThing.js │ │ ├── useAllThings.js │ │ ├── useCurrentThing.js │ │ ├── useData.js │ │ └── useThing.js │ ├── main.jsx │ └── things │ │ ├── AddAThing.jsx │ │ ├── AllThings.jsx │ │ ├── Button.jsx │ │ ├── Grid.jsx │ │ ├── Progress.jsx │ │ ├── RemoveButton.jsx │ │ ├── SingleThing.jsx │ │ ├── Thing.jsx │ │ ├── ThingTitle.jsx │ │ ├── Things.jsx │ │ └── index.js │ └── vite.config.js ├── ch09 ├── better-reactive │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ └── mockServiceWorker.js │ ├── src │ │ ├── App.jsx │ │ ├── backend │ │ │ └── index.js │ │ ├── data │ │ │ ├── DataProvider.jsx │ │ │ ├── Loader.jsx │ │ │ ├── api │ │ │ │ ├── api.js │ │ │ │ ├── useAddThing.js │ │ │ │ ├── useDoThing.js │ │ │ │ ├── useLoginSignup.js │ │ │ │ ├── useLogout.js │ │ │ │ ├── useRemoveThing.js │ │ │ │ └── useUndoThing.js │ │ │ ├── index.js │ │ │ ├── useAllThings.js │ │ │ ├── useCurrent.js │ │ │ ├── useHasCurrent.js │ │ │ ├── useThatThing.js │ │ │ ├── useThisThing.js │ │ │ └── useUser.js │ │ ├── main.jsx │ │ └── view │ │ │ ├── AddAThing.jsx │ │ │ ├── AllThings.jsx │ │ │ ├── Button.jsx │ │ │ ├── Form.jsx │ │ │ ├── Grid.jsx │ │ │ ├── Login.jsx │ │ │ ├── LoginSignup.jsx │ │ │ ├── Logout.jsx │ │ │ ├── Progress.jsx │ │ │ ├── RemoveButton.jsx │ │ │ ├── Signup.jsx │ │ │ ├── SingleThing.jsx │ │ │ ├── Thing.jsx │ │ │ ├── ThingTitle.jsx │ │ │ ├── Things.jsx │ │ │ ├── View.jsx │ │ │ └── index.js │ └── vite.config.js ├── reactive │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ └── mockServiceWorker.js │ ├── src │ │ ├── App.jsx │ │ ├── backend │ │ │ └── index.js │ │ ├── data │ │ │ ├── DataProvider.jsx │ │ │ ├── Loader.jsx │ │ │ ├── api │ │ │ │ ├── api.js │ │ │ │ ├── useAddThing.js │ │ │ │ ├── useDoThing.js │ │ │ │ ├── useLoginSignup.js │ │ │ │ ├── useLogout.js │ │ │ │ ├── useRemoveThing.js │ │ │ │ └── useUndoThing.js │ │ │ ├── index.js │ │ │ ├── useAllThings.js │ │ │ ├── useCurrent.js │ │ │ ├── useHasCurrent.js │ │ │ ├── useThatThing.js │ │ │ ├── useThisThing.js │ │ │ └── useUser.js │ │ ├── main.jsx │ │ └── view │ │ │ ├── AddAThing.jsx │ │ │ ├── AllThings.jsx │ │ │ ├── Button.jsx │ │ │ ├── Form.jsx │ │ │ ├── Grid.jsx │ │ │ ├── Login.jsx │ │ │ ├── LoginSignup.jsx │ │ │ ├── Logout.jsx │ │ │ ├── Progress.jsx │ │ │ ├── RemoveButton.jsx │ │ │ ├── Signup.jsx │ │ │ ├── SingleThing.jsx │ │ │ ├── Thing.jsx │ │ │ ├── ThingTitle.jsx │ │ │ ├── Things.jsx │ │ │ ├── View.jsx │ │ │ └── index.js │ └── vite.config.js └── things │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ └── mockServiceWorker.js │ ├── src │ ├── App.jsx │ ├── backend │ │ └── index.js │ ├── data │ │ ├── DataContext.js │ │ ├── DataProvider.jsx │ │ ├── Loader.jsx │ │ ├── index.js │ │ ├── useAPI.js │ │ ├── useAddThing.js │ │ ├── useAllThings.js │ │ ├── useCurrentThing.js │ │ ├── useData.js │ │ ├── useLoginSignup.js │ │ ├── useLogout.js │ │ ├── useThatThing.js │ │ ├── useThisThing.js │ │ └── useUser.js │ ├── main.jsx │ └── view │ │ ├── AddAThing.jsx │ │ ├── AllThings.jsx │ │ ├── Button.jsx │ │ ├── Form.jsx │ │ ├── Grid.jsx │ │ ├── Login.jsx │ │ ├── LoginSignup.jsx │ │ ├── Logout.jsx │ │ ├── Progress.jsx │ │ ├── RemoveButton.jsx │ │ ├── Signup.jsx │ │ ├── SingleThing.jsx │ │ ├── Thing.jsx │ │ ├── ThingTitle.jsx │ │ ├── Things.jsx │ │ ├── View.jsx │ │ └── index.js │ └── vite.config.js ├── ch10 ├── axios │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── StarshipList.jsx │ │ ├── StarshipList.test.jsx │ │ └── main.jsx │ └── vite.config.js ├── click-counter │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── Counter.jsx │ │ ├── Counter.test.jsx │ │ └── main.jsx │ └── vite.config.js ├── dark-mode │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── Button.jsx │ │ ├── Button.test.jsx │ │ ├── DarkModeContext.jsx │ │ ├── Header.jsx │ │ ├── Page.jsx │ │ ├── ToggleButton.jsx │ │ ├── ToggleButton.test.jsx │ │ └── main.jsx │ └── vite.config.js ├── geo │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── WhereAmI.jsx │ │ ├── WhereAmI.test.jsx │ │ └── main.jsx │ └── vite.config.js ├── keypress │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── main.jsx │ │ ├── useIsKeyPressed.js │ │ └── useIsKeyPressed.test.js │ └── vite.config.js ├── menuitem-icon │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ └── images │ │ │ └── link.png │ ├── src │ │ ├── App.jsx │ │ ├── MenuItem.jsx │ │ ├── MenuItem.test.jsx │ │ └── main.jsx │ └── vite.config.js ├── menuitem │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── MenuItem.jsx │ │ ├── MenuItem.test.jsx │ │ └── main.jsx │ └── vite.config.js ├── timer │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ └── icons │ │ │ ├── pause.svg │ │ │ ├── play.svg │ │ │ ├── restart.svg │ │ │ └── trash.svg │ ├── src │ │ ├── AddTimer.jsx │ │ ├── AddTimer.test.jsx │ │ ├── App.jsx │ │ ├── Button.jsx │ │ ├── Input.jsx │ │ ├── Number.jsx │ │ ├── TimeDisplay.jsx │ │ ├── Timer.jsx │ │ ├── TimerManager.jsx │ │ ├── main.jsx │ │ ├── style.css │ │ └── useTimer.js │ └── vite.config.js └── todo │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ ├── App.jsx │ ├── Items.jsx │ ├── Items.test.jsx │ ├── Todo.jsx │ └── main.jsx │ └── vite.config.js ├── ch11 ├── nextjs │ ├── .env │ ├── .env.example │ ├── .eslintrc.json │ ├── .gitignore │ ├── README.md │ ├── components │ │ ├── cityCard.js │ │ ├── cityCard.module.css │ │ ├── cityCardList.js │ │ ├── cityDisplay.js │ │ ├── cityDisplay.module.css │ │ ├── getWeatherImage.js │ │ ├── index.js │ │ ├── myCity.js │ │ ├── myCity.module.css │ │ ├── swap.js │ │ └── swap.module.css │ ├── format │ │ ├── context.js │ │ ├── formatProvider.js │ │ ├── index.js │ │ ├── useTemperature.js │ │ └── useTime.js │ ├── jsconfig.json │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── pages │ │ ├── [cc] │ │ │ ├── [city].js │ │ │ └── index.js │ │ ├── _app.js │ │ ├── api │ │ │ └── geocode.js │ │ └── index.js │ ├── prisma │ │ ├── countries.mjs │ │ ├── data.db │ │ ├── migrations │ │ │ ├── 20221117222351_init │ │ │ │ └── migration.sql │ │ │ ├── 20221118201753_latlng │ │ │ │ └── migration.sql │ │ │ ├── 20221118232851_citydata │ │ │ │ └── migration.sql │ │ │ ├── 20221119001055_invert │ │ │ │ └── migration.sql │ │ │ ├── 20221119002223_lowername │ │ │ │ └── migration.sql │ │ │ ├── 20221119002453_uniquecity │ │ │ │ └── migration.sql │ │ │ ├── 20221119003016_namedindex │ │ │ │ └── migration.sql │ │ │ ├── 20221121191205_cc │ │ │ │ └── migration.sql │ │ │ └── migration_lock.toml │ │ ├── schema.prisma │ │ └── seed.mjs │ ├── public │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── icons │ │ │ └── swap.svg │ │ ├── mstile-144x144.png │ │ ├── mstile-150x150.png │ │ ├── mstile-310x150.png │ │ ├── mstile-310x310.png │ │ ├── mstile-70x70.png │ │ ├── safari-pinned-tab.svg │ │ ├── site.webmanifest │ │ └── weathers │ │ │ ├── cloudy.png │ │ │ ├── dreary.png │ │ │ ├── night.png │ │ │ ├── rainy.png │ │ │ ├── snowy.png │ │ │ ├── sunny.png │ │ │ ├── thunder.png │ │ │ └── windy.png │ ├── services │ │ ├── api.js │ │ ├── cookies.js │ │ └── data.js │ └── styles │ │ └── globals.css └── remix │ ├── .env.example │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierignore │ ├── app │ ├── components │ │ ├── cityCard.js │ │ ├── cityCard.module.css │ │ ├── cityCardList.jsx │ │ ├── cityDisplay.jsx │ │ ├── cityDisplay.module.css │ │ ├── getWeatherImage.js │ │ ├── myCity.jsx │ │ ├── myCity.module.css │ │ ├── swap.jsx │ │ └── swap.module.css │ ├── cookies.server.js │ ├── db.server.ts │ ├── entry.client.tsx │ ├── entry.server.tsx │ ├── format │ │ ├── context.js │ │ ├── formatProvider.js │ │ ├── index.js │ │ ├── useTemperature.js │ │ └── useTime.js │ ├── globals.css │ ├── globals.json │ ├── root.jsx │ ├── routes │ │ ├── $cc.$city.jsx │ │ ├── $cc.index.jsx │ │ ├── _index.js │ │ └── api.geocode.js │ ├── services │ │ ├── api.js │ │ ├── cookies.js │ │ └── data.js │ └── singleton.server.ts │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── prisma │ ├── countries.mjs │ ├── migrations │ │ ├── 20221122003110_init │ │ │ └── migration.sql │ │ └── migration_lock.toml │ ├── schema.prisma │ └── seed.mjs │ ├── public │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── browserconfig.xml │ ├── favicon copy.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── fonts │ │ ├── montserrat-v25-latin-100.eot │ │ ├── montserrat-v25-latin-100.svg │ │ ├── montserrat-v25-latin-100.ttf │ │ ├── montserrat-v25-latin-100.woff │ │ └── montserrat-v25-latin-100.woff2 │ ├── icons │ │ └── swap.svg │ ├── mstile-144x144.png │ ├── mstile-150x150.png │ ├── mstile-310x150.png │ ├── mstile-310x310.png │ ├── mstile-70x70.png │ ├── safari-pinned-tab.svg │ ├── site.webmanifest │ └── weathers │ │ ├── cloudy.png │ │ ├── dreary.png │ │ ├── night.png │ │ ├── rainy.png │ │ ├── snowy.png │ │ ├── sunny.png │ │ ├── thunder.png │ │ └── windy.png │ ├── remix.config.js │ ├── remix.env.d.ts │ ├── test │ └── setup-test-env.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── ch12 ├── backend-only │ ├── .env.example │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierignore │ ├── app │ │ ├── components │ │ │ ├── Body.module.css │ │ │ ├── Body.tsx │ │ │ ├── FormMenuItem.tsx │ │ │ ├── Main.module.css │ │ │ ├── Main.tsx │ │ │ ├── Menu.module.css │ │ │ ├── Menu.tsx │ │ │ └── MenuItem.tsx │ │ ├── db.server.ts │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── models │ │ │ ├── category.server.ts │ │ │ ├── expense.server.ts │ │ │ ├── types.client.ts │ │ │ └── user.server.ts │ │ ├── root.css │ │ ├── root.tsx │ │ ├── routes │ │ │ ├── _index.tsx │ │ │ ├── expenses.add.tsx │ │ │ ├── expenses.tsx │ │ │ ├── income.tsx │ │ │ ├── join.tsx │ │ │ ├── login.tsx │ │ │ └── logout.tsx │ │ ├── session.server.ts │ │ ├── singleton.server.ts │ │ ├── utils.test.ts │ │ └── utils.ts │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── prisma │ │ ├── migrations │ │ │ ├── 20221015205634_init │ │ │ │ └── migration.sql │ │ │ └── migration_lock.toml │ │ ├── schema.prisma │ │ └── seed.ts │ ├── public │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon copy.ico │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── fonts │ │ │ ├── montserrat-v25-latin-100.eot │ │ │ ├── montserrat-v25-latin-100.svg │ │ │ ├── montserrat-v25-latin-100.ttf │ │ │ ├── montserrat-v25-latin-100.woff │ │ │ └── montserrat-v25-latin-100.woff2 │ │ ├── icons │ │ │ └── swap.svg │ │ ├── mstile-144x144.png │ │ ├── mstile-150x150.png │ │ ├── mstile-310x150.png │ │ ├── mstile-310x310.png │ │ ├── mstile-70x70.png │ │ ├── safari-pinned-tab.svg │ │ ├── site.webmanifest │ │ └── weathers │ │ │ ├── cloudy.png │ │ │ ├── dreary.png │ │ │ ├── night.png │ │ │ ├── rainy.png │ │ │ ├── snowy.png │ │ │ ├── sunny.png │ │ │ ├── thunder.png │ │ │ └── windy.png │ ├── remix.config.js │ ├── remix.env.d.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── complete │ ├── .env.example │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierignore │ ├── app │ │ ├── components │ │ │ ├── Balance.module.css │ │ │ ├── Balance.tsx │ │ │ ├── Body.module.css │ │ │ ├── Body.tsx │ │ │ ├── Dialog.module.css │ │ │ ├── Dialog.tsx │ │ │ ├── Expenses.module.css │ │ │ ├── Expenses.tsx │ │ │ ├── Form.module.css │ │ │ ├── Form.tsx │ │ │ ├── FormMenuItem.tsx │ │ │ ├── IncomeInput.module.css │ │ │ ├── IncomeInput.tsx │ │ │ ├── Main.module.css │ │ │ ├── Main.tsx │ │ │ ├── Menu.module.css │ │ │ ├── Menu.tsx │ │ │ ├── MenuItem.tsx │ │ │ ├── PieChart.module.css │ │ │ └── PieChart.tsx │ │ ├── db.server.ts │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── models │ │ │ ├── category.server.ts │ │ │ ├── expense.server.ts │ │ │ ├── types.client.ts │ │ │ └── user.server.ts │ │ ├── root.css │ │ ├── root.tsx │ │ ├── routes │ │ │ ├── _index.tsx │ │ │ ├── expenses.add.tsx │ │ │ ├── expenses.tsx │ │ │ ├── income.tsx │ │ │ ├── join.tsx │ │ │ ├── login.tsx │ │ │ └── logout.tsx │ │ ├── session.server.ts │ │ ├── singleton.server.ts │ │ ├── utils.test.ts │ │ └── utils.ts │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── prisma │ │ ├── migrations │ │ │ ├── 20221015205634_init │ │ │ │ └── migration.sql │ │ │ └── migration_lock.toml │ │ ├── schema.prisma │ │ └── seed.ts │ ├── public │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon copy.ico │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── fonts │ │ │ ├── montserrat-v25-latin-100.eot │ │ │ ├── montserrat-v25-latin-100.svg │ │ │ ├── montserrat-v25-latin-100.ttf │ │ │ ├── montserrat-v25-latin-100.woff │ │ │ └── montserrat-v25-latin-100.woff2 │ │ ├── icons │ │ │ └── swap.svg │ │ ├── mstile-144x144.png │ │ ├── mstile-150x150.png │ │ ├── mstile-310x150.png │ │ ├── mstile-310x310.png │ │ ├── mstile-70x70.png │ │ ├── safari-pinned-tab.svg │ │ ├── site.webmanifest │ │ └── weathers │ │ │ ├── cloudy.png │ │ │ ├── dreary.png │ │ │ ├── night.png │ │ │ ├── rainy.png │ │ │ ├── snowy.png │ │ │ ├── sunny.png │ │ │ ├── thunder.png │ │ │ └── windy.png │ ├── remix.config.js │ ├── remix.env.d.ts │ └── tsconfig.json ├── frontend-only │ ├── .env.example │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierignore │ ├── app │ │ ├── components │ │ │ ├── Balance.module.css │ │ │ ├── Balance.tsx │ │ │ ├── Body.module.css │ │ │ ├── Body.tsx │ │ │ ├── Dialog.module.css │ │ │ ├── Dialog.tsx │ │ │ ├── Expenses.module.css │ │ │ ├── Expenses.tsx │ │ │ ├── Form.module.css │ │ │ ├── Form.tsx │ │ │ ├── FormMenuItem.tsx │ │ │ ├── IncomeInput.module.css │ │ │ ├── IncomeInput.tsx │ │ │ ├── Main.module.css │ │ │ ├── Main.tsx │ │ │ ├── Menu.module.css │ │ │ ├── Menu.tsx │ │ │ ├── MenuItem.tsx │ │ │ ├── PieChart.module.css │ │ │ └── PieChart.tsx │ │ ├── db.server.ts │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── models │ │ │ └── user.server.ts │ │ ├── root.css │ │ ├── root.tsx │ │ ├── routes │ │ │ ├── _index.tsx │ │ │ ├── expenses.add.tsx │ │ │ ├── expenses.tsx │ │ │ ├── income.tsx │ │ │ ├── join.tsx │ │ │ ├── login.tsx │ │ │ └── logout.tsx │ │ ├── session.server.ts │ │ ├── singleton.server.ts │ │ ├── utils.test.ts │ │ └── utils.ts │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── prisma │ │ ├── migrations │ │ │ ├── 20221015205634_init │ │ │ │ └── migration.sql │ │ │ └── migration_lock.toml │ │ ├── schema.prisma │ │ └── seed.ts │ ├── public │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon copy.ico │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── fonts │ │ │ ├── montserrat-v25-latin-100.eot │ │ │ ├── montserrat-v25-latin-100.svg │ │ │ ├── montserrat-v25-latin-100.ttf │ │ │ ├── montserrat-v25-latin-100.woff │ │ │ └── montserrat-v25-latin-100.woff2 │ │ ├── icons │ │ │ └── swap.svg │ │ ├── mstile-144x144.png │ │ ├── mstile-150x150.png │ │ ├── mstile-310x150.png │ │ ├── mstile-310x310.png │ │ ├── mstile-70x70.png │ │ ├── safari-pinned-tab.svg │ │ ├── site.webmanifest │ │ └── weathers │ │ │ ├── cloudy.png │ │ │ ├── dreary.png │ │ │ ├── night.png │ │ │ ├── rainy.png │ │ │ ├── snowy.png │ │ │ ├── sunny.png │ │ │ ├── thunder.png │ │ │ └── windy.png │ ├── remix.config.js │ ├── remix.env.d.ts │ ├── tsconfig.json │ └── vitest.config.ts └── skeleton │ ├── .env.example │ ├── .eslintrc.js │ ├── .gitignore │ ├── .prettierignore │ ├── app │ ├── db.server.ts │ ├── entry.client.tsx │ ├── entry.server.tsx │ ├── models │ │ └── user.server.ts │ ├── root.tsx │ ├── routes │ │ ├── _index.tsx │ │ ├── join.tsx │ │ ├── login.tsx │ │ └── logout.tsx │ ├── session.server.ts │ ├── singleton.server.ts │ ├── utils.test.ts │ └── utils.ts │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── prisma │ ├── migrations │ │ ├── 20221015205634_init │ │ │ └── migration.sql │ │ └── migration_lock.toml │ ├── schema.prisma │ └── seed.ts │ ├── public │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── browserconfig.xml │ ├── favicon copy.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── fonts │ │ ├── montserrat-v25-latin-100.eot │ │ ├── montserrat-v25-latin-100.svg │ │ ├── montserrat-v25-latin-100.ttf │ │ ├── montserrat-v25-latin-100.woff │ │ └── montserrat-v25-latin-100.woff2 │ ├── icons │ │ └── swap.svg │ ├── mstile-144x144.png │ ├── mstile-150x150.png │ ├── mstile-310x150.png │ ├── mstile-310x310.png │ ├── mstile-70x70.png │ ├── safari-pinned-tab.svg │ ├── site.webmanifest │ └── weathers │ │ ├── cloudy.png │ │ ├── dreary.png │ │ ├── night.png │ │ ├── rainy.png │ │ ├── snowy.png │ │ ├── sunny.png │ │ ├── thunder.png │ │ └── windy.png │ ├── remix.config.js │ ├── remix.env.d.ts │ ├── tsconfig.json │ └── vitest.config.ts ├── ch13 ├── base │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .storybook │ │ ├── main.js │ │ └── preview.jsx │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.jsx │ │ ├── library │ │ │ ├── button │ │ │ │ ├── Button.jsx │ │ │ │ ├── Button.stories.jsx │ │ │ │ ├── Button.test.jsx │ │ │ │ ├── ButtonGroup.stories.jsx │ │ │ │ ├── ButtonGroup.test.jsx │ │ │ │ └── index.js │ │ │ └── index.js │ │ └── main.jsx │ ├── vite.config.js │ └── vitest.setup.js └── complete │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .storybook │ ├── main.js │ └── preview.jsx │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ ├── App.jsx │ ├── library │ │ ├── accordion │ │ │ ├── Accordion.jsx │ │ │ ├── Accordion.stories.jsx │ │ │ ├── Accordion.test.jsx │ │ │ ├── AccordionContext.jsx │ │ │ ├── AccordionItem.jsx │ │ │ ├── index.js │ │ │ ├── useAccordionContext.js │ │ │ └── useKeyboard.js │ │ ├── button │ │ │ ├── Button.jsx │ │ │ ├── Button.stories.jsx │ │ │ ├── Button.test.jsx │ │ │ ├── ButtonGroup.stories.jsx │ │ │ ├── ButtonGroup.test.jsx │ │ │ └── index.js │ │ ├── index.js │ │ ├── switch │ │ │ ├── Switch.jsx │ │ │ ├── Switch.stories.jsx │ │ │ ├── Switch.test.jsx │ │ │ └── index.js │ │ └── toast │ │ │ ├── Toast.jsx │ │ │ ├── Toast.stories.jsx │ │ │ ├── Toast.test.jsx │ │ │ ├── ToastMaster.jsx │ │ │ ├── ToastProvider.jsx │ │ │ ├── context.js │ │ │ ├── index.js │ │ │ └── useToast.js │ └── main.jsx │ ├── vite.config.js │ └── vitest.setup.js ├── ch14 └── wordle │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .storybook │ ├── main.ts │ └── preview.tsx │ ├── README.md │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── App.tsx │ ├── WordGame.tsx │ ├── components │ │ ├── game │ │ │ ├── Game.tsx │ │ │ ├── gameMachine.ts │ │ │ ├── index.ts │ │ │ └── useGameMachine.ts │ │ ├── gamedata │ │ │ ├── GameDataProvider.tsx │ │ │ ├── context.ts │ │ │ ├── index.ts │ │ │ ├── persistProfile.ts │ │ │ ├── useGameData.ts │ │ │ ├── useGameDialogs.ts │ │ │ └── useProfile.ts │ │ ├── grid │ │ │ ├── Cell.stories.jsx │ │ │ ├── Cell.tsx │ │ │ ├── Grid.stories.jsx │ │ │ ├── Grid.tsx │ │ │ ├── RevealRow.stories.jsx │ │ │ ├── RevealRow.tsx │ │ │ ├── Row.stories.jsx │ │ │ ├── Row.tsx │ │ │ ├── WinRow.stories.jsx │ │ │ ├── WinRow.tsx │ │ │ └── useEffectMachine.ts │ │ ├── keyboard │ │ │ ├── Key.stories.jsx │ │ │ ├── Key.tsx │ │ │ ├── Keyboard.stories.jsx │ │ │ ├── Keyboard.tsx │ │ │ └── useHandleCharacter.ts │ │ ├── menu │ │ │ ├── Menu.tsx │ │ │ └── index.ts │ │ └── overlay │ │ │ ├── Dialog.tsx │ │ │ ├── OverlayProvider.tsx │ │ │ ├── context.ts │ │ │ ├── dialogs │ │ │ ├── Countdown.tsx │ │ │ ├── ResultDialog.tsx │ │ │ ├── WelcomeDialog.tsx │ │ │ └── styles.tsx │ │ │ ├── index.ts │ │ │ ├── useAlert.ts │ │ │ └── useDialog.tsx │ ├── main.tsx │ ├── styles │ │ ├── GlobalStyles.tsx │ │ ├── Provider.tsx │ │ ├── emotion.d.ts │ │ ├── index.ts │ │ └── theme.ts │ ├── types.ts │ ├── utils │ │ ├── constants.ts │ │ ├── getLabel.ts │ │ ├── getToday.ts │ │ ├── getWordOfTheDay.ts │ │ ├── goodWords.ts │ │ ├── isValidWord.ts │ │ ├── localStorage.ts │ │ ├── tryWord.test.ts │ │ ├── tryWord.ts │ │ ├── updateKeyboard.ts │ │ └── validWords.ts │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── package-lock.json ├── package.json └── scripts ├── build.js └── create.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /base-projects/vite-base-js/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /base-projects/vite-base-js/src/App.jsx: -------------------------------------------------------------------------------- 1 | export default function App() { 2 | return ( 3 |
4 |

Vite Example with JS

5 |
6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /base-projects/vite-base-js/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /base-projects/vite-base-js/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /base-projects/vite-base-ts/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /base-projects/vite-base-ts/src/App.tsx: -------------------------------------------------------------------------------- 1 | export default function App() { 2 | return ( 3 |
4 |

Vite Example with TS

5 |
6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /base-projects/vite-base-ts/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")!).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /base-projects/vite-base-ts/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /base-projects/vite-base-ts/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /base-projects/vite-base-ts/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch02/dark-mode-dedicated/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch02/dark-mode-dedicated/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch02/dark-mode-dedicated/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch02/dark-mode-selector/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch02/dark-mode-selector/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch02/dark-mode-selector/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch02/dark-mode-typed/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch02/dark-mode-typed/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")!).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch02/dark-mode-typed/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch02/dark-mode-typed/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /ch02/dark-mode-typed/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch02/dark-mode/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch02/dark-mode/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch02/dark-mode/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch02/radio-complex/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch02/radio-complex/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch02/radio-complex/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch02/radio-composite/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch02/radio-composite/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch02/radio-composite/src/radiogroup/Details.jsx: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { RadioOptionContext } from "./contexts"; 3 | 4 | export function Details({ children }) { 5 | const isSelected = useContext(RadioOptionContext); 6 | return isSelected ? children : null; 7 | } 8 | -------------------------------------------------------------------------------- /ch02/radio-composite/src/radiogroup/contexts.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const RadioGroupContext = createContext(); 4 | export const RadioOptionContext = createContext(); 5 | -------------------------------------------------------------------------------- /ch02/radio-composite/src/radiogroup/index.js: -------------------------------------------------------------------------------- 1 | export { RadioGroup } from "./RadioGroup"; 2 | -------------------------------------------------------------------------------- /ch02/radio-composite/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch02/radio-simple/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch02/radio-simple/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch02/radio-simple/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch02/radio-summary/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch02/radio-summary/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch02/radio-summary/src/radiogroup/Details.jsx: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { RadioOptionContext } from "./contexts"; 3 | 4 | export function Details({ children }) { 5 | const isSelected = useContext(RadioOptionContext); 6 | return isSelected ? children : null; 7 | } 8 | -------------------------------------------------------------------------------- /ch02/radio-summary/src/radiogroup/contexts.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const RadioGroupContext = createContext(); 4 | export const RadioOptionContext = createContext(); 5 | -------------------------------------------------------------------------------- /ch02/radio-summary/src/radiogroup/index.js: -------------------------------------------------------------------------------- 1 | export { RadioGroup } from "./RadioGroup"; 2 | -------------------------------------------------------------------------------- /ch02/radio-summary/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch02/task-summary/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch02/task-summary/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { LongTaskManager } from "./LongTaskManager"; 2 | 3 | export default function App() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /ch02/task-summary/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch02/task-summary/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch02/user-summary/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch02/user-summary/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { LongUserProfile } from "./LongUserProfile"; 2 | 3 | export default function App() { 4 | return ( 5 |
6 | 7 |
8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /ch02/user-summary/src/UserDetails.jsx: -------------------------------------------------------------------------------- 1 | export function UserDetails({ userData }) { 2 | return ( 3 |
4 |

Personal Information

5 |

6 | Name: {userData.name} 7 |

8 |

9 | Email: {userData.email} 10 |

11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /ch02/user-summary/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch02/user-summary/src/useAPI.js: -------------------------------------------------------------------------------- 1 | import { useMemo } from "react"; 2 | 3 | export function useAPI() { 4 | return useMemo( 5 | () => ({ 6 | fetchUser: (userId) => 7 | fetch(`https://api.company.invalid/users/${userId}`), 8 | }), 9 | [] 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /ch02/user-summary/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch03/employees/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch03/employees/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch03/employees/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch03/rerender/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch03/rerender/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | rerender from React in Depth 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch03/rerender/src/NoRerenderWithPropsChange.jsx: -------------------------------------------------------------------------------- 1 | import { useRef } from "react"; 2 | import { Rerenderable } from "./Rerenderable"; 3 | 4 | export function NoRerenderWithPropsChange() { 5 | const count = useRef(0); 6 | return ( 7 |
8 | 11 | 12 |
13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /ch03/rerender/src/RerenderWithoutPropsChange.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { Rerenderable } from "./Rerenderable"; 3 | 4 | export function RerenderWithoutPropsChange() { 5 | const [, setCount] = useState(0); 6 | return ( 7 |
8 | 11 | 12 |
13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /ch03/rerender/src/Rerenderable.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useRef } from "react"; 3 | 4 | export function Rerenderable() { 5 | const isFirst = useRef(true); 6 | useEffect(() => { 7 | isFirst.current = false; 8 | }, []); 9 | const style = { color: isFirst.current ? "red" : "blue" }; 10 | const text = isFirst.current ? "First render" : "Not first render"; 11 | return

{text}

; 12 | } 13 | -------------------------------------------------------------------------------- /ch03/rerender/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch03/rerender/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch03/strict-mode/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch03/strict-mode/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch03/strict-mode/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch03/todo-delete/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch03/todo-delete/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch03/todo-delete/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch03/todo-fixed/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch03/todo-fixed/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch03/todo-fixed/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch03/todo-memo/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch03/todo-memo/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch03/todo-memo/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch03/todo-simple/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch03/todo-simple/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch03/todo-simple/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch03/todo-usememo/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch03/todo-usememo/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch03/todo-usememo/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch04/dark-mode/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch04/dark-mode/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch04/dark-mode/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch04/prettier/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch04/prettier/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | prettier from React in Depth 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch04/prettier/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch04/prettier/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch05/book-review/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch05/book-review/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /ch05/book-review/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch05/book-review/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /ch05/book-review/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch05/employee/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch05/employee/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | employee from React in Depth 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch05/employee/src/App.tsx: -------------------------------------------------------------------------------- 1 | import EmployeeCard from "./EmployeeCard"; 2 | import "./app.css"; 3 | 4 | function App() { 5 | return ( 6 |
7 | 10 |
11 | ); 12 | } 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /ch05/employee/src/app.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@300&display=swap"); 2 | 3 | * { 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | background-color: #eee; 9 | font-family: "Open Sans", sans-serif; 10 | } 11 | 12 | main { 13 | display: flex; 14 | align-items: center; 15 | justify-content: center; 16 | margin: 2em; 17 | } 18 | -------------------------------------------------------------------------------- /ch05/employee/src/employee.css: -------------------------------------------------------------------------------- 1 | .employee { 2 | background: white; 3 | flex: 0 0 300px; 4 | border-radius: 1em; 5 | padding: 1em 1.5em; 6 | box-shadow: 4px 4px 2px rgba(0 0 0 / 0.2); 7 | } 8 | .employee__name { 9 | margin: 0 0 0.5em; 10 | font-size: 24px; 11 | } 12 | .employee__title { 13 | margin: 0; 14 | text-transform: uppercase; 15 | font-size: 16px; 16 | color: #222; 17 | } 18 | -------------------------------------------------------------------------------- /ch05/employee/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")!).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch05/employee/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch05/employee/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /ch05/employee/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch05/employees/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch05/employees/src/app.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@300&display=swap"); 2 | 3 | * { 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | background-color: #eee; 9 | font-family: "Open Sans", sans-serif; 10 | } 11 | 12 | main { 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | margin: 2em; 18 | gap: 1em; 19 | } 20 | -------------------------------------------------------------------------------- /ch05/employees/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")!).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch05/employees/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch05/employees/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /ch05/employees/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch05/product-card/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch05/product-card/src/App.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | background-color: #f4f4f4; 6 | color: #333; 7 | } 8 | 9 | main { 10 | width: 100%; 11 | padding: 20px; 12 | display: flex; 13 | flex-direction: column; 14 | align-items: center; 15 | gap: 20px; 16 | } 17 | -------------------------------------------------------------------------------- /ch05/product-card/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | } 6 | 7 | *, 8 | *::before, 9 | *::after { 10 | box-sizing: border-box; 11 | } 12 | -------------------------------------------------------------------------------- /ch05/product-card/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /ch05/product-card/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch05/product-card/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /ch05/product-card/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch06/appointment/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch06/appointment/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { AppointmentResponse } from "./AppointmentResponse"; 2 | 3 | function App() { 4 | return ( 5 | <> 6 |

Incoming appointment

7 |

From: John Doe

8 |

Date: 2021-09-01

9 | 10 | 11 | ); 12 | } 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /ch06/appointment/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | font-synthesis: none; 7 | text-rendering: optimizeLegibility; 8 | -webkit-font-smoothing: antialiased; 9 | -moz-osx-font-smoothing: grayscale; 10 | -webkit-text-size-adjust: 100%; 11 | } 12 | -------------------------------------------------------------------------------- /ch06/appointment/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /ch06/appointment/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch06/appointment/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /ch06/appointment/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch06/dark-mode/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch06/dark-mode/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")!).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch06/dark-mode/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch06/dark-mode/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /ch06/dark-mode/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch06/paginable/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch06/paginable/src/EmployeeCard.tsx: -------------------------------------------------------------------------------- 1 | import "./employee.css"; 2 | import { Employee } from "./types"; 3 | 4 | interface CardProps { 5 | item: Employee; 6 | } 7 | 8 | export function EmployeeCard({ item }: CardProps) { 9 | return ( 10 |
11 |

{item.name}

12 |

{item.title}

13 |
14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /ch06/paginable/src/employee.css: -------------------------------------------------------------------------------- 1 | .employee { 2 | background: white; 3 | flex: 0 0 300px; 4 | border-radius: 1em; 5 | padding: 1em 1.5em; 6 | box-shadow: 4px 4px 2px rgba(0 0 0 / 0.2); 7 | } 8 | .employee__name { 9 | margin: 0 0 0.5em; 10 | font-size: 24px; 11 | } 12 | .employee__title { 13 | margin: 0; 14 | text-transform: uppercase; 15 | font-size: 16px; 16 | color: #222; 17 | } 18 | -------------------------------------------------------------------------------- /ch06/paginable/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")!).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch06/paginable/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface Employee { 2 | name: string; 3 | title: string; 4 | } 5 | 6 | export interface Entry { 7 | name: string; 8 | points: number; 9 | } 10 | -------------------------------------------------------------------------------- /ch06/paginable/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch06/paginable/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /ch06/paginable/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch06/playlist/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch06/playlist/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")!).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch06/playlist/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface Song { 2 | id: number; 3 | title: string; 4 | artist: string; 5 | } 6 | 7 | export type Action = 8 | | { type: "up"; index: number } 9 | | { type: "down"; index: number } 10 | | { type: "first"; index: number } 11 | | { type: "last"; index: number }; 12 | 13 | export type ActionType = Action["type"]; 14 | -------------------------------------------------------------------------------- /ch06/playlist/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch06/playlist/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /ch06/playlist/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch06/tag-form/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch06/tag-form/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | tag-form from React in Depth 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch06/tag-form/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { TagForm } from "./TagForm"; 2 | 3 | export default function App() { 4 | return ( 5 |
6 | {}} /> 7 |
8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /ch06/tag-form/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")!).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch06/tag-form/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch06/tag-form/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /ch06/tag-form/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch06/use-reorderable/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch06/use-reorderable/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")!).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch06/use-reorderable/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch06/use-reorderable/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /ch06/use-reorderable/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch07/classnames/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch07/classnames/src/app.css: -------------------------------------------------------------------------------- 1 | .custom-button { 2 | background-color: purple; 3 | border-color: purple; 4 | } 5 | -------------------------------------------------------------------------------- /ch07/classnames/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch07/classnames/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch07/cssmodules/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch07/cssmodules/src/app.module.css: -------------------------------------------------------------------------------- 1 | button.customButton { 2 | background-color: purple; 3 | border-color: purple; 4 | } 5 | -------------------------------------------------------------------------------- /ch07/cssmodules/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch07/cssmodules/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch07/inline/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch07/inline/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | inline from React in Depth 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch07/inline/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch07/inline/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch07/styled/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch07/styled/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | styled from React in Depth 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch07/styled/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch07/styled/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch07/tailwind/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch07/tailwind/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | tailwind from React in Depth 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch07/tailwind/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /ch07/tailwind/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind components; 2 | @tailwind utilities; 3 | -------------------------------------------------------------------------------- /ch07/tailwind/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch07/tailwind/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch08/context/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch08/context/src/data/DataContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const DataContext = createContext({ state: {}, actions: {} }); 4 | -------------------------------------------------------------------------------- /ch08/context/src/data/index.js: -------------------------------------------------------------------------------- 1 | export { DataProvider } from "./DataProvider"; 2 | export { useAddThing } from "./useAddThing"; 3 | export { useAllThings } from "./useAllThings"; 4 | export { useThing } from "./useThing"; 5 | export { useCurrentThing } from "./useCurrentThing"; 6 | -------------------------------------------------------------------------------- /ch08/context/src/data/useAddThing.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useAddThing() { 4 | return useData().actions.addThing; 5 | } 6 | -------------------------------------------------------------------------------- /ch08/context/src/data/useAllThings.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useAllThings() { 4 | return useData().state.things.map(({ id }) => id); 5 | } 6 | -------------------------------------------------------------------------------- /ch08/context/src/data/useCurrentThing.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useCurrentThing() { 4 | return useData().state.currentThing; 5 | } 6 | -------------------------------------------------------------------------------- /ch08/context/src/data/useData.js: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { DataContext } from "./DataContext"; 3 | 4 | export function useData() { 5 | return useContext(DataContext); 6 | } 7 | -------------------------------------------------------------------------------- /ch08/context/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch08/context/src/things/Things.jsx: -------------------------------------------------------------------------------- 1 | import { useCurrentThing } from "../data"; 2 | import { AllThings } from "./AllThings"; 3 | import { SingleThing } from "./SingleThing"; 4 | 5 | export function Things() { 6 | const currentThing = useCurrentThing(); 7 | if (currentThing) { 8 | return ; 9 | } 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /ch08/context/src/things/index.js: -------------------------------------------------------------------------------- 1 | export { Things } from "./Things"; 2 | -------------------------------------------------------------------------------- /ch08/context/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch08/reducer/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch08/reducer/src/data/DataContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "use-context-selector"; 2 | 3 | export const DataContext = createContext({}); 4 | -------------------------------------------------------------------------------- /ch08/reducer/src/data/index.js: -------------------------------------------------------------------------------- 1 | export { DataProvider } from "./DataProvider"; 2 | export { useAddThing } from "./useAddThing"; 3 | export { useAllThings } from "./useAllThings"; 4 | export { useThing } from "./useThing"; 5 | export { useCurrentThing } from "./useCurrentThing"; 6 | -------------------------------------------------------------------------------- /ch08/reducer/src/data/useAddThing.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useAddThing() { 4 | return useData(({ actions }) => actions.addThing); 5 | } 6 | -------------------------------------------------------------------------------- /ch08/reducer/src/data/useAllThings.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useAllThings() { 4 | return useData(({ state }) => state.things).map(({ id }) => id); 5 | } 6 | -------------------------------------------------------------------------------- /ch08/reducer/src/data/useCurrentThing.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useCurrentThing() { 4 | return useData(({ state }) => state.currentThing); 5 | } 6 | -------------------------------------------------------------------------------- /ch08/reducer/src/data/useData.js: -------------------------------------------------------------------------------- 1 | import { useContextSelector } from "use-context-selector"; 2 | import { DataContext } from "./DataContext"; 3 | 4 | export function useData(selector) { 5 | return useContextSelector(DataContext, selector); 6 | } 7 | -------------------------------------------------------------------------------- /ch08/reducer/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch08/reducer/src/things/Things.jsx: -------------------------------------------------------------------------------- 1 | import { useCurrentThing } from "../data"; 2 | import { AllThings } from "./AllThings"; 3 | import { SingleThing } from "./SingleThing"; 4 | 5 | export function Things() { 6 | const currentThing = useCurrentThing(); 7 | if (currentThing) { 8 | return ; 9 | } 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /ch08/reducer/src/things/index.js: -------------------------------------------------------------------------------- 1 | export { Things } from "./Things"; 2 | -------------------------------------------------------------------------------- /ch08/reducer/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch08/redux/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch08/redux/src/data/index.js: -------------------------------------------------------------------------------- 1 | export { DataProvider } from "./DataProvider"; 2 | export { useAddThing } from "./useAddThing"; 3 | export { useAllThings } from "./useAllThings"; 4 | export { useThing } from "./useThing"; 5 | export { useCurrentThing } from "./useCurrentThing"; 6 | -------------------------------------------------------------------------------- /ch08/redux/src/data/useAddThing.js: -------------------------------------------------------------------------------- 1 | import { actions } from "./store"; 2 | import { useDispatch } from "react-redux"; 3 | 4 | export function useAddThing() { 5 | const dispatch = useDispatch(); 6 | return (name) => dispatch(actions.addThing(name)); 7 | } 8 | -------------------------------------------------------------------------------- /ch08/redux/src/data/useAllThings.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useAllThings() { 4 | return useData((store) => store.data.things).map(({ id }) => id); 5 | } 6 | -------------------------------------------------------------------------------- /ch08/redux/src/data/useCurrentThing.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useCurrentThing() { 4 | return useData((store) => store.data.currentThing); 5 | } 6 | -------------------------------------------------------------------------------- /ch08/redux/src/data/useData.js: -------------------------------------------------------------------------------- 1 | import { useSelector } from "react-redux"; 2 | 3 | export function useData(selector) { 4 | return useSelector(selector); 5 | } 6 | -------------------------------------------------------------------------------- /ch08/redux/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch08/redux/src/things/Things.jsx: -------------------------------------------------------------------------------- 1 | import { useCurrentThing } from "../data"; 2 | import { AllThings } from "./AllThings"; 3 | import { SingleThing } from "./SingleThing"; 4 | 5 | export function Things() { 6 | const currentThing = useCurrentThing(); 7 | if (currentThing) { 8 | return ; 9 | } 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /ch08/redux/src/things/index.js: -------------------------------------------------------------------------------- 1 | export { Things } from "./Things"; 2 | -------------------------------------------------------------------------------- /ch08/redux/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch08/xstate/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch08/xstate/src/data/DataContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const DataContext = createContext({}); 4 | -------------------------------------------------------------------------------- /ch08/xstate/src/data/index.js: -------------------------------------------------------------------------------- 1 | export { DataProvider } from "./DataProvider"; 2 | export { useAddThing } from "./useAddThing"; 3 | export { useAllThings } from "./useAllThings"; 4 | export { useThatThing } from "./useThatThing"; 5 | export { useThisThing } from "./useThisThing"; 6 | export { useCurrentThing } from "./useCurrentThing"; 7 | -------------------------------------------------------------------------------- /ch08/xstate/src/data/useAddThing.js: -------------------------------------------------------------------------------- 1 | import { useSend } from "./useSend"; 2 | 3 | export function useAddThing() { 4 | const send = useSend(); 5 | return (name) => send({ type: "ADD", name }); 6 | } 7 | -------------------------------------------------------------------------------- /ch08/xstate/src/data/useAllThings.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useAllThings() { 4 | return useData((state) => state.context.things).map(({ id }) => id); 5 | } 6 | -------------------------------------------------------------------------------- /ch08/xstate/src/data/useCurrentThing.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useCurrentThing() { 4 | return useData(({ context }) => context.currentThing); 5 | } 6 | -------------------------------------------------------------------------------- /ch08/xstate/src/data/useData.js: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { DataContext } from "./DataContext"; 3 | import { useSelector } from "@xstate/react"; 4 | 5 | export function useData(selector) { 6 | const service = useContext(DataContext); 7 | return useSelector(service, selector); 8 | } 9 | -------------------------------------------------------------------------------- /ch08/xstate/src/data/useSend.js: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { DataContext } from "./DataContext"; 3 | 4 | export function useSend() { 5 | return useContext(DataContext).send; 6 | } 7 | -------------------------------------------------------------------------------- /ch08/xstate/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch08/xstate/src/things/Things.jsx: -------------------------------------------------------------------------------- 1 | import { useCurrentThing } from "../data"; 2 | import { AllThings } from "./AllThings"; 3 | import { SingleThing } from "./SingleThing"; 4 | 5 | export function Things() { 6 | const currentThing = useCurrentThing(); 7 | if (currentThing) { 8 | return ; 9 | } 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /ch08/xstate/src/things/index.js: -------------------------------------------------------------------------------- 1 | export { Things } from "./Things"; 2 | -------------------------------------------------------------------------------- /ch08/xstate/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch08/zustand/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch08/zustand/src/data/DataProvider.jsx: -------------------------------------------------------------------------------- 1 | import "./useData"; 2 | export function DataProvider({ children }) { 3 | return children; 4 | } 5 | -------------------------------------------------------------------------------- /ch08/zustand/src/data/index.js: -------------------------------------------------------------------------------- 1 | export { DataProvider } from "./DataProvider"; 2 | export { useAddThing } from "./useAddThing"; 3 | export { useAllThings } from "./useAllThings"; 4 | export { useThing } from "./useThing"; 5 | export { useCurrentThing } from "./useCurrentThing"; 6 | -------------------------------------------------------------------------------- /ch08/zustand/src/data/useAddThing.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useAddThing() { 4 | return useData((state) => state.addThing); 5 | } 6 | -------------------------------------------------------------------------------- /ch08/zustand/src/data/useAllThings.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useAllThings() { 4 | return useData((state) => state.things).map(({ id }) => id); 5 | } 6 | -------------------------------------------------------------------------------- /ch08/zustand/src/data/useCurrentThing.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useCurrentThing() { 4 | return useData((state) => state.currentThing); 5 | } 6 | -------------------------------------------------------------------------------- /ch08/zustand/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch08/zustand/src/things/Things.jsx: -------------------------------------------------------------------------------- 1 | import { useCurrentThing } from "../data"; 2 | import { AllThings } from "./AllThings"; 3 | import { SingleThing } from "./SingleThing"; 4 | 5 | export function Things() { 6 | const currentThing = useCurrentThing(); 7 | if (currentThing) { 8 | return ; 9 | } 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /ch08/zustand/src/things/index.js: -------------------------------------------------------------------------------- 1 | export { Things } from "./Things"; 2 | -------------------------------------------------------------------------------- /ch08/zustand/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch09/better-reactive/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/data/DataProvider.jsx: -------------------------------------------------------------------------------- 1 | import { 2 | QueryClient, 3 | QueryClientProvider, 4 | } from "@tanstack/react-query"; 5 | import { Loader } from "./Loader"; 6 | 7 | const queryClient = new QueryClient(); 8 | 9 | export function DataProvider({ children }) { 10 | return ( 11 | 12 | 13 | {children} 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/data/api/useDoThing.js: -------------------------------------------------------------------------------- 1 | import { useMutation } from "@tanstack/react-query"; 2 | import * as API from "./api"; 3 | 4 | export function useDoThing(onSuccess) { 5 | const { mutate: doThing } = useMutation({ 6 | mutationFn: API.doThing, 7 | onSuccess, 8 | }); 9 | return doThing; 10 | } 11 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/data/api/useLogout.js: -------------------------------------------------------------------------------- 1 | import { useQueryClient, useMutation } from "@tanstack/react-query"; 2 | import * as API from "./api"; 3 | 4 | export function useLogout() { 5 | const queryClient = useQueryClient(); 6 | const onSuccess = () => queryClient.setQueryData(["user"], null); 7 | const { mutate: logout } = useMutation({ 8 | mutationFn: API.logout, 9 | onSuccess, 10 | }); 11 | return logout; 12 | } 13 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/data/api/useUndoThing.js: -------------------------------------------------------------------------------- 1 | import { useMutation } from "@tanstack/react-query"; 2 | import * as API from "./api"; 3 | 4 | export function useUndoThing(onSuccess) { 5 | const { mutate: undoThing } = useMutation({ 6 | mutationFn: API.undoThing, 7 | onSuccess, 8 | }); 9 | return undoThing; 10 | } 11 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/data/useAllThings.js: -------------------------------------------------------------------------------- 1 | import { useQuery } from "@tanstack/react-query"; 2 | import { loadThings } from "./api/api"; 3 | 4 | export function useAllThings() { 5 | const { data = [] } = useQuery({ 6 | queryKey: ["things"], 7 | queryFn: loadThings, 8 | }); 9 | return data.map(({ id }) => id) || []; 10 | } 11 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/data/useCurrent.js: -------------------------------------------------------------------------------- 1 | import { create } from "zustand"; 2 | 3 | export const useCurrent = create((set) => ({ 4 | currentId: null, 5 | seeThing: (id) => set(() => ({ currentId: id })), 6 | seeAllThings: () => set(() => ({ currentId: null })), 7 | })); 8 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/data/useHasCurrent.js: -------------------------------------------------------------------------------- 1 | import { useCurrent } from "./useCurrent"; 2 | 3 | export function useHasCurrent() { 4 | return useCurrent((state) => !!state.currentId); 5 | } 6 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/data/useUser.js: -------------------------------------------------------------------------------- 1 | import { useQuery } from "@tanstack/react-query"; 2 | import { getUser } from "./api/api"; 3 | 4 | export function useUser() { 5 | const { data } = useQuery({ 6 | queryKey: ["user"], 7 | queryFn: getUser, 8 | }); 9 | return data; 10 | } 11 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | import { worker } from "./backend"; 5 | 6 | worker.start(); 7 | 8 | ReactDOM.createRoot(document.getElementById("root")).render( 9 | 10 | 11 | 12 | ); 13 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/view/Logout.jsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { useLogout } from "../data"; 3 | import { Button } from "./Button"; 4 | 5 | const LogoutButton = styled(Button)` 6 | display: flex; 7 | align-self: flex-end; 8 | `; 9 | 10 | export function Logout() { 11 | const logout = useLogout(); 12 | return Log out; 13 | } 14 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/view/Things.jsx: -------------------------------------------------------------------------------- 1 | import { useHasCurrent } from "../data"; 2 | import { AllThings } from "./AllThings"; 3 | import { SingleThing } from "./SingleThing"; 4 | 5 | export function Things() { 6 | const hasCurrent = useHasCurrent(); 7 | if (hasCurrent) { 8 | return ; 9 | } 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/view/View.jsx: -------------------------------------------------------------------------------- 1 | import { useUser } from "../data"; 2 | import { Things } from "./Things"; 3 | import { LoginSignup } from "./LoginSignup"; 4 | 5 | export function View() { 6 | const hasUser = useUser(); 7 | if (hasUser) { 8 | return ; 9 | } 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /ch09/better-reactive/src/view/index.js: -------------------------------------------------------------------------------- 1 | export { View } from "./View"; 2 | -------------------------------------------------------------------------------- /ch09/better-reactive/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch09/reactive/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch09/reactive/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | reactive from React in Depth 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch09/reactive/src/data/DataProvider.jsx: -------------------------------------------------------------------------------- 1 | import { 2 | QueryClient, 3 | QueryClientProvider, 4 | } from "@tanstack/react-query"; 5 | import { Loader } from "./Loader"; 6 | 7 | const queryClient = new QueryClient(); 8 | 9 | export function DataProvider({ children }) { 10 | return ( 11 | 12 | 13 | {children} 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /ch09/reactive/src/data/useAllThings.js: -------------------------------------------------------------------------------- 1 | import { useQuery } from "@tanstack/react-query"; 2 | import { loadThings } from "./api/api"; 3 | 4 | export function useAllThings() { 5 | const { data } = useQuery({ 6 | queryKey: ["things"], 7 | queryFn: loadThings, 8 | }); 9 | return data?.map(({ id }) => id) || []; 10 | } 11 | -------------------------------------------------------------------------------- /ch09/reactive/src/data/useCurrent.js: -------------------------------------------------------------------------------- 1 | import { create } from "zustand"; 2 | 3 | export const useCurrent = create((set) => ({ 4 | currentId: null, 5 | seeThing: (id) => set(() => ({ currentId: id })), 6 | seeAllThings: () => set(() => ({ currentId: null })), 7 | })); 8 | -------------------------------------------------------------------------------- /ch09/reactive/src/data/useHasCurrent.js: -------------------------------------------------------------------------------- 1 | import { useCurrent } from "./useCurrent"; 2 | 3 | export function useHasCurrent() { 4 | return useCurrent((state) => !!state.currentId); 5 | } 6 | -------------------------------------------------------------------------------- /ch09/reactive/src/data/useUser.js: -------------------------------------------------------------------------------- 1 | import { useQuery } from "@tanstack/react-query"; 2 | import { getUser } from "./api/api"; 3 | 4 | export function useUser() { 5 | const { data } = useQuery({ 6 | queryKey: ["user"], 7 | queryFn: getUser, 8 | }); 9 | return data; 10 | } 11 | -------------------------------------------------------------------------------- /ch09/reactive/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | import { worker } from "./backend"; 5 | 6 | worker.start(); 7 | 8 | ReactDOM.createRoot(document.getElementById("root")).render( 9 | 10 | 11 | 12 | ); 13 | -------------------------------------------------------------------------------- /ch09/reactive/src/view/Logout.jsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { useLogout } from "../data"; 3 | import { Button } from "./Button"; 4 | 5 | const LogoutButton = styled(Button)` 6 | display: flex; 7 | align-self: flex-end; 8 | `; 9 | 10 | export function Logout() { 11 | const logout = useLogout(); 12 | return Log out; 13 | } 14 | -------------------------------------------------------------------------------- /ch09/reactive/src/view/Things.jsx: -------------------------------------------------------------------------------- 1 | import { useHasCurrent } from "../data"; 2 | import { AllThings } from "./AllThings"; 3 | import { SingleThing } from "./SingleThing"; 4 | 5 | export function Things() { 6 | const hasCurrent = useHasCurrent(); 7 | if (hasCurrent) { 8 | return ; 9 | } 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /ch09/reactive/src/view/View.jsx: -------------------------------------------------------------------------------- 1 | import { useUser } from "../data"; 2 | import { Things } from "./Things"; 3 | import { LoginSignup } from "./LoginSignup"; 4 | 5 | export function View() { 6 | const hasUser = useUser(); 7 | if (hasUser) { 8 | return ; 9 | } 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /ch09/reactive/src/view/index.js: -------------------------------------------------------------------------------- 1 | export { View } from "./View"; 2 | -------------------------------------------------------------------------------- /ch09/reactive/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch09/things/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch09/things/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | things from React in Depth 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch09/things/src/data/DataContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "use-context-selector"; 2 | 3 | export const DataContext = createContext({ state: {}, actions: {} }); 4 | -------------------------------------------------------------------------------- /ch09/things/src/data/useAddThing.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useAddThing() { 4 | return useData(({ actions }) => actions.addThing); 5 | } 6 | -------------------------------------------------------------------------------- /ch09/things/src/data/useAllThings.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useData } from "./useData"; 3 | 4 | export function useAllThings() { 5 | const loadThings = useData(({ actions }) => actions.loadThings); 6 | useEffect(() => void loadThings(), [loadThings]); 7 | return useData(({ state }) => state.things).map(({ id }) => id); 8 | } 9 | -------------------------------------------------------------------------------- /ch09/things/src/data/useCurrentThing.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useCurrentThing() { 4 | return useData(({ state }) => state.currentId); 5 | } 6 | -------------------------------------------------------------------------------- /ch09/things/src/data/useData.js: -------------------------------------------------------------------------------- 1 | import { useContextSelector } from "use-context-selector"; 2 | import { DataContext } from "./DataContext"; 3 | 4 | export function useData(selector) { 5 | return useContextSelector(DataContext, selector ?? ((i) => i)); 6 | } 7 | -------------------------------------------------------------------------------- /ch09/things/src/data/useLoginSignup.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useLoginSignup() { 4 | const login = useData(({ actions }) => actions.login); 5 | const signup = useData(({ actions }) => actions.signup); 6 | return { login, signup }; 7 | } 8 | -------------------------------------------------------------------------------- /ch09/things/src/data/useLogout.js: -------------------------------------------------------------------------------- 1 | import { useData } from "./useData"; 2 | 3 | export function useLogout() { 4 | const logout = useData(({ actions }) => actions.logout); 5 | return logout; 6 | } 7 | -------------------------------------------------------------------------------- /ch09/things/src/data/useUser.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useData } from "./useData"; 3 | 4 | export function useUser() { 5 | const getUser = useData(({ actions }) => actions.getUser); 6 | const isAuthorized = useData(({ state }) => state.isAuthorized); 7 | useEffect(() => void getUser(), [getUser]); 8 | return isAuthorized; 9 | } 10 | -------------------------------------------------------------------------------- /ch09/things/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | import { worker } from "./backend"; 5 | 6 | worker.start(); 7 | 8 | ReactDOM.createRoot(document.getElementById("root")).render( 9 | 10 | 11 | 12 | ); 13 | -------------------------------------------------------------------------------- /ch09/things/src/view/Logout.jsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { useLogout } from "../data"; 3 | import { Button } from "./Button"; 4 | 5 | const LogoutButton = styled(Button)` 6 | display: flex; 7 | align-self: flex-end; 8 | `; 9 | 10 | export function Logout() { 11 | const logout = useLogout(); 12 | return Log out; 13 | } 14 | -------------------------------------------------------------------------------- /ch09/things/src/view/Things.jsx: -------------------------------------------------------------------------------- 1 | import { useCurrentThing } from "../data"; 2 | import { AllThings } from "./AllThings"; 3 | import { SingleThing } from "./SingleThing"; 4 | 5 | export function Things() { 6 | const currentThing = useCurrentThing(); 7 | if (currentThing) { 8 | return ; 9 | } 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /ch09/things/src/view/View.jsx: -------------------------------------------------------------------------------- 1 | import { useUser } from "../data"; 2 | import { Things } from "./Things"; 3 | import { LoginSignup } from "./LoginSignup"; 4 | 5 | export function View() { 6 | const hasUser = useUser(); 7 | if (hasUser) { 8 | return ; 9 | } 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /ch09/things/src/view/index.js: -------------------------------------------------------------------------------- 1 | export { View } from "./View"; 2 | -------------------------------------------------------------------------------- /ch09/things/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /ch10/axios/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch10/axios/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | axios from React in Depth 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch10/axios/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { StarshipList } from "./StarshipList"; 2 | 3 | export default function App() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /ch10/axios/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch10/axios/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { globals: true, environment: "jsdom" }, 8 | }); 9 | -------------------------------------------------------------------------------- /ch10/click-counter/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch10/click-counter/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { Counter } from "./Counter"; 2 | 3 | export default function App() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /ch10/click-counter/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch10/click-counter/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { globals: true, environment: "jsdom" }, 8 | }); 9 | -------------------------------------------------------------------------------- /ch10/dark-mode/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch10/dark-mode/src/DarkModeContext.jsx: -------------------------------------------------------------------------------- 1 | import { createContext } from "use-context-selector"; 2 | 3 | export const DarkModeContext = createContext({}); 4 | -------------------------------------------------------------------------------- /ch10/dark-mode/src/ToggleButton.jsx: -------------------------------------------------------------------------------- 1 | import { useContextSelector } from "use-context-selector"; 2 | import { Button } from "./Button"; 3 | import { DarkModeContext } from "./DarkModeContext"; 4 | 5 | export function ToggleButton() { 6 | const toggleDarkMode = useContextSelector( 7 | DarkModeContext, 8 | (contextValue) => contextValue.toggleDarkMode 9 | ); 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /ch10/dark-mode/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch10/dark-mode/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { globals: true, environment: "jsdom" }, 8 | }); 9 | -------------------------------------------------------------------------------- /ch10/geo/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch10/geo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | geo from React in Depth 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch10/geo/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { WhereAmI } from "./WhereAmI.jsx"; 2 | 3 | export default function App() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /ch10/geo/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch10/geo/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { globals: true, environment: "jsdom" }, 8 | }); 9 | -------------------------------------------------------------------------------- /ch10/keypress/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch10/keypress/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { useIsKeyPressed } from "./useIsKeyPressed"; 2 | 3 | export default function App() { 4 | const isShiftDown = useIsKeyPressed("Shift"); 5 | return ( 6 |
7 |

8 | is Shift currently pressed down? 9 |

10 |

{isShiftDown ? "YES" : "NO"}

11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /ch10/keypress/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch10/keypress/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { globals: true, environment: "jsdom" }, 8 | }); 9 | -------------------------------------------------------------------------------- /ch10/menuitem-icon/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch10/menuitem-icon/public/images/link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch10/menuitem-icon/public/images/link.png -------------------------------------------------------------------------------- /ch10/menuitem-icon/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { MenuItem } from "./MenuItem"; 2 | 3 | export default function App() { 4 | return ( 5 |
    6 | 7 | 8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /ch10/menuitem-icon/src/MenuItem.jsx: -------------------------------------------------------------------------------- 1 | export function MenuItem({ href, label }) { 2 | return ( 3 |
  • 4 | 5 | 6 | {label} 7 | 8 |
  • 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /ch10/menuitem-icon/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch10/menuitem-icon/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { globals: true, environment: "jsdom" }, 8 | }); 9 | -------------------------------------------------------------------------------- /ch10/menuitem/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch10/menuitem/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { MenuItem } from "./MenuItem"; 2 | 3 | export default function App() { 4 | return ( 5 |
      6 | 7 | 8 |
    9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /ch10/menuitem/src/MenuItem.jsx: -------------------------------------------------------------------------------- 1 | export function MenuItem({ href, label }) { 2 | return ( 3 |
  • 4 | 5 | {label} 6 | 7 |
  • 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /ch10/menuitem/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch10/menuitem/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { globals: true, environment: "jsdom" }, 8 | }); 9 | -------------------------------------------------------------------------------- /ch10/timer/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch10/timer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | timer from React in Depth 8 | 9 | 10 |
    11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch10/timer/src/App.jsx: -------------------------------------------------------------------------------- 1 | import "./style.css"; 2 | 3 | import { TimerManager } from "./TimerManager"; 4 | 5 | export default function App() { 6 | return ( 7 |
    8 |

    Countdown

    9 | 10 |
    11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /ch10/timer/src/Button.jsx: -------------------------------------------------------------------------------- 1 | import { memo } from "react"; 2 | 3 | export const Button = memo(function Button({ icon, label, ...rest }) { 4 | return ( 5 | 8 | ); 9 | }); 10 | -------------------------------------------------------------------------------- /ch10/timer/src/Number.jsx: -------------------------------------------------------------------------------- 1 | export function Number({ value, label }) { 2 | return ( 3 |
  • 4 |

    {String(value).padStart(2, "0")}

    5 |

    {label}

    6 |
  • 7 | ); 8 | } 9 | -------------------------------------------------------------------------------- /ch10/timer/src/TimeDisplay.jsx: -------------------------------------------------------------------------------- 1 | import { Number } from "./Number"; 2 | 3 | export function TimeDisplay({ time }) { 4 | const minutes = Math.floor(time / 60); 5 | const seconds = time % 60; 6 | 7 | return ( 8 |
      9 | 10 |
    • :
    • 11 | 12 |
    13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /ch10/timer/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch10/timer/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { globals: true, environment: "jsdom" }, 8 | }); 9 | -------------------------------------------------------------------------------- /ch10/todo/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch10/todo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | todo from React in Depth 8 | 9 | 10 |
    11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch10/todo/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { Todo } from "./Todo"; 2 | 3 | export default function App() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /ch10/todo/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch10/todo/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { globals: true, environment: "jsdom" }, 8 | }); 9 | -------------------------------------------------------------------------------- /ch11/nextjs/.env: -------------------------------------------------------------------------------- 1 | NEXT_TELEMETRY_DISABLED=1 -------------------------------------------------------------------------------- /ch11/nextjs/.env.example: -------------------------------------------------------------------------------- 1 | OPENWEATHER_API_KEY="" 2 | DATABASE_URL="file:./data.db?connection_limit=1" -------------------------------------------------------------------------------- /ch11/nextjs/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/babel", "next/core-web-vitals"] 3 | } 4 | -------------------------------------------------------------------------------- /ch11/nextjs/components/index.js: -------------------------------------------------------------------------------- 1 | export { Swap } from "./swap"; 2 | export { getWeatherImage } from "./getWeatherImage"; 3 | export { CityCard } from "./cityCard"; 4 | export { CityCardList } from "./cityCardList"; 5 | export { CityDisplay } from "./cityDisplay"; 6 | export { MyCity } from "./myCity"; 7 | -------------------------------------------------------------------------------- /ch11/nextjs/components/myCity.module.css: -------------------------------------------------------------------------------- 1 | .link { 2 | text-decoration: underline; 3 | } 4 | -------------------------------------------------------------------------------- /ch11/nextjs/components/swap.js: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import styles from "./swap.module.css"; 3 | 4 | export function Swap({ title, ...rest }) { 5 | return ( 6 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /ch11/nextjs/components/swap.module.css: -------------------------------------------------------------------------------- 1 | .swap { 2 | background: none; 3 | border: 0; 4 | padding: 0; 5 | cursor: pointer; 6 | position: relative; 7 | top: -0.8em; 8 | } 9 | -------------------------------------------------------------------------------- /ch11/nextjs/format/context.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const FormatContext = createContext({}); 4 | -------------------------------------------------------------------------------- /ch11/nextjs/format/index.js: -------------------------------------------------------------------------------- 1 | export { FormatProvider } from "./formatProvider"; 2 | export { useTemperature } from "./useTemperature"; 3 | export { useTime } from "./useTime"; 4 | -------------------------------------------------------------------------------- /ch11/nextjs/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ch11/nextjs/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /ch11/nextjs/prisma/data.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/prisma/data.db -------------------------------------------------------------------------------- /ch11/nextjs/prisma/migrations/20221119002453_uniquecity/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - A unique constraint covering the columns `[countryId,lowerName]` on the table `City` will be added. If there are existing duplicate values, this will fail. 5 | 6 | */ 7 | -- CreateIndex 8 | CREATE UNIQUE INDEX "City_countryId_lowerName_key" ON "City"("countryId", "lowerName"); 9 | -------------------------------------------------------------------------------- /ch11/nextjs/prisma/migrations/20221119003016_namedindex/migration.sql: -------------------------------------------------------------------------------- 1 | -- This is an empty migration. -------------------------------------------------------------------------------- /ch11/nextjs/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /ch11/nextjs/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /ch11/nextjs/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /ch11/nextjs/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/apple-touch-icon.png -------------------------------------------------------------------------------- /ch11/nextjs/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ch11/nextjs/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/favicon-16x16.png -------------------------------------------------------------------------------- /ch11/nextjs/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/favicon-32x32.png -------------------------------------------------------------------------------- /ch11/nextjs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/favicon.ico -------------------------------------------------------------------------------- /ch11/nextjs/public/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/mstile-144x144.png -------------------------------------------------------------------------------- /ch11/nextjs/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/mstile-150x150.png -------------------------------------------------------------------------------- /ch11/nextjs/public/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/mstile-310x150.png -------------------------------------------------------------------------------- /ch11/nextjs/public/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/mstile-310x310.png -------------------------------------------------------------------------------- /ch11/nextjs/public/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/mstile-70x70.png -------------------------------------------------------------------------------- /ch11/nextjs/public/weathers/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/cloudy.png -------------------------------------------------------------------------------- /ch11/nextjs/public/weathers/dreary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/dreary.png -------------------------------------------------------------------------------- /ch11/nextjs/public/weathers/night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/night.png -------------------------------------------------------------------------------- /ch11/nextjs/public/weathers/rainy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/rainy.png -------------------------------------------------------------------------------- /ch11/nextjs/public/weathers/snowy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/snowy.png -------------------------------------------------------------------------------- /ch11/nextjs/public/weathers/sunny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/sunny.png -------------------------------------------------------------------------------- /ch11/nextjs/public/weathers/thunder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/thunder.png -------------------------------------------------------------------------------- /ch11/nextjs/public/weathers/windy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/nextjs/public/weathers/windy.png -------------------------------------------------------------------------------- /ch11/nextjs/services/cookies.js: -------------------------------------------------------------------------------- 1 | import { getCookie } from "cookies-next"; 2 | 3 | export function getDefaultFormats(context) { 4 | const isCelsius = getCookie("nextjs-isCelsius", context); 5 | const hour12 = getCookie("nextjs-hour12", context); 6 | return { 7 | isCelsius: isCelsius !== "false", 8 | hour12: hour12 === "true", 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /ch11/remix/.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL="file:./data.db?connection_limit=1" 2 | SESSION_SECRET="super-duper-s3cret" 3 | OPENWEATHER_API_KEY="" 4 | -------------------------------------------------------------------------------- /ch11/remix/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | 7 | /cypress/screenshots 8 | /cypress/videos 9 | /prisma/data.db 10 | /prisma/data.db-journal 11 | 12 | /app/styles/ -------------------------------------------------------------------------------- /ch11/remix/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | 7 | /app/styles/tailwind.css 8 | -------------------------------------------------------------------------------- /ch11/remix/app/components/myCity.module.css: -------------------------------------------------------------------------------- 1 | .link { 2 | text-decoration: underline; 3 | } 4 | -------------------------------------------------------------------------------- /ch11/remix/app/components/swap.module.css: -------------------------------------------------------------------------------- 1 | .button { 2 | background: none; 3 | border: 0; 4 | padding: 0; 5 | cursor: pointer; 6 | position: relative; 7 | top: -0.8em; 8 | } 9 | .form { 10 | display: inline; 11 | } 12 | -------------------------------------------------------------------------------- /ch11/remix/app/cookies.server.js: -------------------------------------------------------------------------------- 1 | import { createCookie } from "@remix-run/node"; 2 | 3 | const maxAge = 86_400 * 365; // one year 4 | export const temperatureCookie = createCookie("temperature", { maxAge }); 5 | export const timeCookie = createCookie("time", { maxAge }); 6 | export const myCityCookie = createCookie("myCity", { maxAge }); 7 | -------------------------------------------------------------------------------- /ch11/remix/app/db.server.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | import { singleton } from "./singleton.server"; 4 | 5 | // Hard-code a unique key, so we can look up the client when this module gets re-imported 6 | const prisma = singleton("prisma", () => new PrismaClient()); 7 | prisma.$connect(); 8 | 9 | export { prisma }; 10 | -------------------------------------------------------------------------------- /ch11/remix/app/format/context.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | const FormatContext = createContext({}); 4 | export default FormatContext; 5 | -------------------------------------------------------------------------------- /ch11/remix/app/format/index.js: -------------------------------------------------------------------------------- 1 | export { default as FormatProvider } from "./formatProvider"; 2 | export { default as useTemperature } from "./useTemperature"; 3 | export { default as useTime } from "./useTime"; 4 | -------------------------------------------------------------------------------- /ch11/remix/app/globals.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /ch11/remix/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /ch11/remix/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /ch11/remix/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /ch11/remix/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /ch11/remix/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/apple-touch-icon.png -------------------------------------------------------------------------------- /ch11/remix/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ch11/remix/public/favicon copy.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/favicon copy.ico -------------------------------------------------------------------------------- /ch11/remix/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/favicon-16x16.png -------------------------------------------------------------------------------- /ch11/remix/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/favicon-32x32.png -------------------------------------------------------------------------------- /ch11/remix/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/favicon.ico -------------------------------------------------------------------------------- /ch11/remix/public/fonts/montserrat-v25-latin-100.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/fonts/montserrat-v25-latin-100.eot -------------------------------------------------------------------------------- /ch11/remix/public/fonts/montserrat-v25-latin-100.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/fonts/montserrat-v25-latin-100.ttf -------------------------------------------------------------------------------- /ch11/remix/public/fonts/montserrat-v25-latin-100.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/fonts/montserrat-v25-latin-100.woff -------------------------------------------------------------------------------- /ch11/remix/public/fonts/montserrat-v25-latin-100.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/fonts/montserrat-v25-latin-100.woff2 -------------------------------------------------------------------------------- /ch11/remix/public/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/mstile-144x144.png -------------------------------------------------------------------------------- /ch11/remix/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/mstile-150x150.png -------------------------------------------------------------------------------- /ch11/remix/public/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/mstile-310x150.png -------------------------------------------------------------------------------- /ch11/remix/public/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/mstile-310x310.png -------------------------------------------------------------------------------- /ch11/remix/public/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/mstile-70x70.png -------------------------------------------------------------------------------- /ch11/remix/public/weathers/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/cloudy.png -------------------------------------------------------------------------------- /ch11/remix/public/weathers/dreary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/dreary.png -------------------------------------------------------------------------------- /ch11/remix/public/weathers/night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/night.png -------------------------------------------------------------------------------- /ch11/remix/public/weathers/rainy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/rainy.png -------------------------------------------------------------------------------- /ch11/remix/public/weathers/snowy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/snowy.png -------------------------------------------------------------------------------- /ch11/remix/public/weathers/sunny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/sunny.png -------------------------------------------------------------------------------- /ch11/remix/public/weathers/thunder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/thunder.png -------------------------------------------------------------------------------- /ch11/remix/public/weathers/windy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch11/remix/public/weathers/windy.png -------------------------------------------------------------------------------- /ch11/remix/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | module.exports = { 3 | cacheDirectory: "./node_modules/.cache/remix", 4 | ignoredRouteFiles: ["**/.*", "**/*.test.{ts,tsx}"], 5 | serverModuleFormat: "cjs", 6 | }; 7 | -------------------------------------------------------------------------------- /ch11/remix/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /ch11/remix/test/setup-test-env.ts: -------------------------------------------------------------------------------- 1 | import { installGlobals } from "@remix-run/node"; 2 | import "@testing-library/jest-dom/vitest"; 3 | 4 | installGlobals(); 5 | -------------------------------------------------------------------------------- /ch12/backend-only/.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL="file:./data.db?connection_limit=1" 2 | SESSION_SECRET="super-duper-s3cret" -------------------------------------------------------------------------------- /ch12/backend-only/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | 7 | /cypress/screenshots 8 | /cypress/videos 9 | /prisma/data.db 10 | /prisma/data.db-journal 11 | 12 | /app/styles/ -------------------------------------------------------------------------------- /ch12/backend-only/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | -------------------------------------------------------------------------------- /ch12/backend-only/app/components/Body.module.css: -------------------------------------------------------------------------------- 1 | .body { 2 | background-color: #ddd; 3 | min-height: 100vh; 4 | display: flex; 5 | justify-content: center; 6 | padding: 1em; 7 | } 8 | -------------------------------------------------------------------------------- /ch12/backend-only/app/components/Body.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren } from "react"; 2 | 3 | import styles from "./body.module.css"; 4 | 5 | export function Body({ children }: PropsWithChildren) { 6 | return {children}; 7 | } 8 | -------------------------------------------------------------------------------- /ch12/backend-only/app/components/Main.module.css: -------------------------------------------------------------------------------- 1 | .main { 2 | background-color: #eee; 3 | border-radius: 1em; 4 | width: 80em; 5 | padding: 0.5em; 6 | } 7 | -------------------------------------------------------------------------------- /ch12/backend-only/app/components/Main.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren } from "react"; 2 | 3 | import styles from "./main.module.css"; 4 | 5 | export function Main({ children }: PropsWithChildren) { 6 | return
    {children}
    ; 7 | } 8 | -------------------------------------------------------------------------------- /ch12/backend-only/app/db.server.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | import { singleton } from "./singleton.server"; 4 | 5 | // Hard-code a unique key, so we can look up the client when this module gets re-imported 6 | const prisma = singleton("prisma", () => new PrismaClient()); 7 | prisma.$connect(); 8 | 9 | export { prisma }; 10 | -------------------------------------------------------------------------------- /ch12/backend-only/app/models/types.client.ts: -------------------------------------------------------------------------------- 1 | export type User = { 2 | id: string; 3 | email: string; 4 | name: string; 5 | categories: Category[]; 6 | expenses: Expense[]; 7 | }; 8 | 9 | export type Category = { 10 | id: string; 11 | name: string; 12 | color: string; 13 | }; 14 | 15 | export type Expense = { 16 | id: string; 17 | item: string; 18 | value: number; 19 | category: Omit; 20 | }; 21 | -------------------------------------------------------------------------------- /ch12/backend-only/app/routes/logout.tsx: -------------------------------------------------------------------------------- 1 | import type { ActionFunctionArgs } from "@remix-run/node"; 2 | import { redirect } from "@remix-run/node"; 3 | 4 | import { logout } from "~/session.server"; 5 | 6 | export async function action({ request }: ActionFunctionArgs) { 7 | return logout(request); 8 | } 9 | 10 | export async function loader() { 11 | return redirect("/"); 12 | } 13 | -------------------------------------------------------------------------------- /ch12/backend-only/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /ch12/backend-only/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /ch12/backend-only/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /ch12/backend-only/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /ch12/backend-only/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/apple-touch-icon.png -------------------------------------------------------------------------------- /ch12/backend-only/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ch12/backend-only/public/favicon copy.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/favicon copy.ico -------------------------------------------------------------------------------- /ch12/backend-only/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/favicon-16x16.png -------------------------------------------------------------------------------- /ch12/backend-only/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/favicon-32x32.png -------------------------------------------------------------------------------- /ch12/backend-only/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/favicon.ico -------------------------------------------------------------------------------- /ch12/backend-only/public/fonts/montserrat-v25-latin-100.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/fonts/montserrat-v25-latin-100.eot -------------------------------------------------------------------------------- /ch12/backend-only/public/fonts/montserrat-v25-latin-100.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/fonts/montserrat-v25-latin-100.ttf -------------------------------------------------------------------------------- /ch12/backend-only/public/fonts/montserrat-v25-latin-100.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/fonts/montserrat-v25-latin-100.woff -------------------------------------------------------------------------------- /ch12/backend-only/public/fonts/montserrat-v25-latin-100.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/fonts/montserrat-v25-latin-100.woff2 -------------------------------------------------------------------------------- /ch12/backend-only/public/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/mstile-144x144.png -------------------------------------------------------------------------------- /ch12/backend-only/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/mstile-150x150.png -------------------------------------------------------------------------------- /ch12/backend-only/public/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/mstile-310x150.png -------------------------------------------------------------------------------- /ch12/backend-only/public/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/mstile-310x310.png -------------------------------------------------------------------------------- /ch12/backend-only/public/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/mstile-70x70.png -------------------------------------------------------------------------------- /ch12/backend-only/public/weathers/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/cloudy.png -------------------------------------------------------------------------------- /ch12/backend-only/public/weathers/dreary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/dreary.png -------------------------------------------------------------------------------- /ch12/backend-only/public/weathers/night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/night.png -------------------------------------------------------------------------------- /ch12/backend-only/public/weathers/rainy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/rainy.png -------------------------------------------------------------------------------- /ch12/backend-only/public/weathers/snowy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/snowy.png -------------------------------------------------------------------------------- /ch12/backend-only/public/weathers/sunny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/sunny.png -------------------------------------------------------------------------------- /ch12/backend-only/public/weathers/thunder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/thunder.png -------------------------------------------------------------------------------- /ch12/backend-only/public/weathers/windy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/backend-only/public/weathers/windy.png -------------------------------------------------------------------------------- /ch12/backend-only/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | module.exports = { 3 | cacheDirectory: "./node_modules/.cache/remix", 4 | ignoredRouteFiles: ["**/.*", "**/*.test.{ts,tsx}"], 5 | serverModuleFormat: "cjs", 6 | }; 7 | -------------------------------------------------------------------------------- /ch12/backend-only/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /ch12/complete/.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL="file:./data.db?connection_limit=1" 2 | SESSION_SECRET="super-duper-s3cret" -------------------------------------------------------------------------------- /ch12/complete/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | 7 | /cypress/screenshots 8 | /cypress/videos 9 | /prisma/data.db 10 | /prisma/data.db-journal 11 | 12 | /app/styles/ -------------------------------------------------------------------------------- /ch12/complete/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | -------------------------------------------------------------------------------- /ch12/complete/app/components/Body.module.css: -------------------------------------------------------------------------------- 1 | .body { 2 | background-color: #ddd; 3 | min-height: 100vh; 4 | display: flex; 5 | justify-content: center; 6 | padding: 1em; 7 | } 8 | -------------------------------------------------------------------------------- /ch12/complete/app/components/Body.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren } from "react"; 2 | 3 | import styles from "./Body.module.css"; 4 | 5 | export function Body({ children }: PropsWithChildren) { 6 | return {children}; 7 | } 8 | -------------------------------------------------------------------------------- /ch12/complete/app/components/Dialog.module.css: -------------------------------------------------------------------------------- 1 | .background { 2 | position: fixed; 3 | inset: 0; 4 | background-color: rgba(0 0 0 / 0.5); 5 | } 6 | 7 | .dialog { 8 | position: absolute; 9 | inset: 1em 50%; 10 | background-color: white; 11 | padding: 1em; 12 | border-radius: 1em; 13 | --width: min(calc(100vw - 2em), 40em); 14 | width: var(--width); 15 | margin-left: calc(var(--width) / -2); 16 | } 17 | -------------------------------------------------------------------------------- /ch12/complete/app/components/Dialog.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren } from "react"; 2 | 3 | import styles from "./Dialog.module.css"; 4 | 5 | export function Dialog({ children }: PropsWithChildren) { 6 | return ( 7 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /ch12/complete/app/components/Main.module.css: -------------------------------------------------------------------------------- 1 | .main { 2 | background-color: #eee; 3 | border-radius: 1em; 4 | width: 80em; 5 | padding: 0.5em; 6 | } 7 | -------------------------------------------------------------------------------- /ch12/complete/app/components/Main.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren } from "react"; 2 | 3 | import styles from "./Main.module.css"; 4 | 5 | export function Main({ children }: PropsWithChildren) { 6 | return
    {children}
    ; 7 | } 8 | -------------------------------------------------------------------------------- /ch12/complete/app/db.server.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | import { singleton } from "./singleton.server"; 4 | 5 | // Hard-code a unique key, so we can look up the client when this module gets re-imported 6 | const prisma = singleton("prisma", () => new PrismaClient()); 7 | prisma.$connect(); 8 | 9 | export { prisma }; 10 | -------------------------------------------------------------------------------- /ch12/complete/app/models/types.client.ts: -------------------------------------------------------------------------------- 1 | export type User = { 2 | id: string; 3 | email: string; 4 | name: string; 5 | categories: Category[]; 6 | expenses: Expense[]; 7 | }; 8 | 9 | export type Category = { 10 | id: string; 11 | name: string; 12 | color: string; 13 | }; 14 | 15 | export type Expense = { 16 | id: string; 17 | item: string; 18 | value: number; 19 | category: Omit; 20 | }; 21 | -------------------------------------------------------------------------------- /ch12/complete/app/routes/logout.tsx: -------------------------------------------------------------------------------- 1 | import type { ActionFunctionArgs } from "@remix-run/node"; 2 | import { redirect } from "@remix-run/node"; 3 | 4 | import { logout } from "~/session.server"; 5 | 6 | export async function action({ request }: ActionFunctionArgs) { 7 | return logout(request); 8 | } 9 | 10 | export async function loader() { 11 | return redirect("/"); 12 | } 13 | -------------------------------------------------------------------------------- /ch12/complete/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /ch12/complete/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /ch12/complete/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /ch12/complete/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /ch12/complete/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/apple-touch-icon.png -------------------------------------------------------------------------------- /ch12/complete/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ch12/complete/public/favicon copy.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/favicon copy.ico -------------------------------------------------------------------------------- /ch12/complete/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/favicon-16x16.png -------------------------------------------------------------------------------- /ch12/complete/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/favicon-32x32.png -------------------------------------------------------------------------------- /ch12/complete/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/favicon.ico -------------------------------------------------------------------------------- /ch12/complete/public/fonts/montserrat-v25-latin-100.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/fonts/montserrat-v25-latin-100.eot -------------------------------------------------------------------------------- /ch12/complete/public/fonts/montserrat-v25-latin-100.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/fonts/montserrat-v25-latin-100.ttf -------------------------------------------------------------------------------- /ch12/complete/public/fonts/montserrat-v25-latin-100.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/fonts/montserrat-v25-latin-100.woff -------------------------------------------------------------------------------- /ch12/complete/public/fonts/montserrat-v25-latin-100.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/fonts/montserrat-v25-latin-100.woff2 -------------------------------------------------------------------------------- /ch12/complete/public/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/mstile-144x144.png -------------------------------------------------------------------------------- /ch12/complete/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/mstile-150x150.png -------------------------------------------------------------------------------- /ch12/complete/public/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/mstile-310x150.png -------------------------------------------------------------------------------- /ch12/complete/public/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/mstile-310x310.png -------------------------------------------------------------------------------- /ch12/complete/public/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/mstile-70x70.png -------------------------------------------------------------------------------- /ch12/complete/public/weathers/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/cloudy.png -------------------------------------------------------------------------------- /ch12/complete/public/weathers/dreary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/dreary.png -------------------------------------------------------------------------------- /ch12/complete/public/weathers/night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/night.png -------------------------------------------------------------------------------- /ch12/complete/public/weathers/rainy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/rainy.png -------------------------------------------------------------------------------- /ch12/complete/public/weathers/snowy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/snowy.png -------------------------------------------------------------------------------- /ch12/complete/public/weathers/sunny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/sunny.png -------------------------------------------------------------------------------- /ch12/complete/public/weathers/thunder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/thunder.png -------------------------------------------------------------------------------- /ch12/complete/public/weathers/windy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/complete/public/weathers/windy.png -------------------------------------------------------------------------------- /ch12/complete/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | module.exports = { 3 | cacheDirectory: "./node_modules/.cache/remix", 4 | ignoredRouteFiles: ["**/.*", "**/*.test.{ts,tsx}"], 5 | serverModuleFormat: "cjs", 6 | }; 7 | -------------------------------------------------------------------------------- /ch12/complete/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /ch12/frontend-only/.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL="file:./data.db?connection_limit=1" 2 | SESSION_SECRET="super-duper-s3cret" -------------------------------------------------------------------------------- /ch12/frontend-only/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | 7 | /cypress/screenshots 8 | /cypress/videos 9 | /prisma/data.db 10 | /prisma/data.db-journal 11 | 12 | /app/styles/ -------------------------------------------------------------------------------- /ch12/frontend-only/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | -------------------------------------------------------------------------------- /ch12/frontend-only/app/components/Body.module.css: -------------------------------------------------------------------------------- 1 | .body { 2 | background-color: #ddd; 3 | min-height: 100vh; 4 | display: flex; 5 | justify-content: center; 6 | padding: 1em; 7 | } 8 | -------------------------------------------------------------------------------- /ch12/frontend-only/app/components/Body.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren } from "react"; 2 | 3 | import styles from "./body.module.css"; 4 | 5 | export function Body({ children }: PropsWithChildren) { 6 | return {children}; 7 | } 8 | -------------------------------------------------------------------------------- /ch12/frontend-only/app/components/Dialog.module.css: -------------------------------------------------------------------------------- 1 | .background { 2 | position: fixed; 3 | inset: 0; 4 | background-color: rgba(0 0 0 / 0.5); 5 | } 6 | 7 | .dialog { 8 | position: absolute; 9 | inset: 1em 50%; 10 | background-color: white; 11 | padding: 1em; 12 | border-radius: 1em; 13 | --width: min(calc(100vw - 2em), 40em); 14 | width: var(--width); 15 | margin-left: calc(var(--width) / -2); 16 | } 17 | -------------------------------------------------------------------------------- /ch12/frontend-only/app/components/Dialog.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren } from "react"; 2 | 3 | import styles from "./Dialog.module.css"; 4 | 5 | export function Dialog({ children }: PropsWithChildren) { 6 | return ( 7 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /ch12/frontend-only/app/components/Main.module.css: -------------------------------------------------------------------------------- 1 | .main { 2 | background-color: #eee; 3 | border-radius: 1em; 4 | width: 80em; 5 | padding: 0.5em; 6 | } 7 | -------------------------------------------------------------------------------- /ch12/frontend-only/app/components/Main.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren } from "react"; 2 | 3 | import styles from "./main.module.css"; 4 | 5 | export function Main({ children }: PropsWithChildren) { 6 | return
    {children}
    ; 7 | } 8 | -------------------------------------------------------------------------------- /ch12/frontend-only/app/db.server.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | import { singleton } from "./singleton.server"; 4 | 5 | // Hard-code a unique key, so we can look up the client when this module gets re-imported 6 | const prisma = singleton("prisma", () => new PrismaClient()); 7 | prisma.$connect(); 8 | 9 | export { prisma }; 10 | -------------------------------------------------------------------------------- /ch12/frontend-only/app/routes/logout.tsx: -------------------------------------------------------------------------------- 1 | import type { ActionFunctionArgs } from "@remix-run/node"; 2 | import { redirect } from "@remix-run/node"; 3 | 4 | import { logout } from "~/session.server"; 5 | 6 | export async function action({ request }: ActionFunctionArgs) { 7 | return logout(request); 8 | } 9 | 10 | export async function loader() { 11 | return redirect("/"); 12 | } 13 | -------------------------------------------------------------------------------- /ch12/frontend-only/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /ch12/frontend-only/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /ch12/frontend-only/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/apple-touch-icon.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ch12/frontend-only/public/favicon copy.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/favicon copy.ico -------------------------------------------------------------------------------- /ch12/frontend-only/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/favicon-16x16.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/favicon-32x32.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/favicon.ico -------------------------------------------------------------------------------- /ch12/frontend-only/public/fonts/montserrat-v25-latin-100.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/fonts/montserrat-v25-latin-100.eot -------------------------------------------------------------------------------- /ch12/frontend-only/public/fonts/montserrat-v25-latin-100.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/fonts/montserrat-v25-latin-100.ttf -------------------------------------------------------------------------------- /ch12/frontend-only/public/fonts/montserrat-v25-latin-100.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/fonts/montserrat-v25-latin-100.woff -------------------------------------------------------------------------------- /ch12/frontend-only/public/fonts/montserrat-v25-latin-100.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/fonts/montserrat-v25-latin-100.woff2 -------------------------------------------------------------------------------- /ch12/frontend-only/public/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/mstile-144x144.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/mstile-150x150.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/mstile-310x150.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/mstile-310x310.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/mstile-70x70.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/weathers/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/cloudy.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/weathers/dreary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/dreary.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/weathers/night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/night.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/weathers/rainy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/rainy.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/weathers/snowy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/snowy.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/weathers/sunny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/sunny.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/weathers/thunder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/thunder.png -------------------------------------------------------------------------------- /ch12/frontend-only/public/weathers/windy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/frontend-only/public/weathers/windy.png -------------------------------------------------------------------------------- /ch12/frontend-only/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | module.exports = { 3 | cacheDirectory: "./node_modules/.cache/remix", 4 | ignoredRouteFiles: ["**/.*", "**/*.test.{ts,tsx}"], 5 | serverModuleFormat: "cjs", 6 | }; 7 | -------------------------------------------------------------------------------- /ch12/frontend-only/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /ch12/skeleton/.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL="file:./data.db?connection_limit=1" 2 | SESSION_SECRET="super-duper-s3cret" -------------------------------------------------------------------------------- /ch12/skeleton/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | 7 | /cypress/screenshots 8 | /cypress/videos 9 | /prisma/data.db 10 | /prisma/data.db-journal 11 | 12 | /app/styles/ -------------------------------------------------------------------------------- /ch12/skeleton/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | -------------------------------------------------------------------------------- /ch12/skeleton/app/db.server.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | import { singleton } from "./singleton.server"; 4 | 5 | // Hard-code a unique key, so we can look up the client when this module gets re-imported 6 | const prisma = singleton("prisma", () => new PrismaClient()); 7 | prisma.$connect(); 8 | 9 | export { prisma }; 10 | -------------------------------------------------------------------------------- /ch12/skeleton/app/routes/logout.tsx: -------------------------------------------------------------------------------- 1 | import type { ActionFunctionArgs } from "@remix-run/node"; 2 | import { redirect } from "@remix-run/node"; 3 | 4 | import { logout } from "~/session.server"; 5 | 6 | export async function action({ request }: ActionFunctionArgs) { 7 | return logout(request); 8 | } 9 | 10 | export async function loader() { 11 | return redirect("/"); 12 | } 13 | -------------------------------------------------------------------------------- /ch12/skeleton/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /ch12/skeleton/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /ch12/skeleton/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /ch12/skeleton/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /ch12/skeleton/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/apple-touch-icon.png -------------------------------------------------------------------------------- /ch12/skeleton/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ch12/skeleton/public/favicon copy.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/favicon copy.ico -------------------------------------------------------------------------------- /ch12/skeleton/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/favicon-16x16.png -------------------------------------------------------------------------------- /ch12/skeleton/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/favicon-32x32.png -------------------------------------------------------------------------------- /ch12/skeleton/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/favicon.ico -------------------------------------------------------------------------------- /ch12/skeleton/public/fonts/montserrat-v25-latin-100.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/fonts/montserrat-v25-latin-100.eot -------------------------------------------------------------------------------- /ch12/skeleton/public/fonts/montserrat-v25-latin-100.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/fonts/montserrat-v25-latin-100.ttf -------------------------------------------------------------------------------- /ch12/skeleton/public/fonts/montserrat-v25-latin-100.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/fonts/montserrat-v25-latin-100.woff -------------------------------------------------------------------------------- /ch12/skeleton/public/fonts/montserrat-v25-latin-100.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/fonts/montserrat-v25-latin-100.woff2 -------------------------------------------------------------------------------- /ch12/skeleton/public/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/mstile-144x144.png -------------------------------------------------------------------------------- /ch12/skeleton/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/mstile-150x150.png -------------------------------------------------------------------------------- /ch12/skeleton/public/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/mstile-310x150.png -------------------------------------------------------------------------------- /ch12/skeleton/public/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/mstile-310x310.png -------------------------------------------------------------------------------- /ch12/skeleton/public/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/mstile-70x70.png -------------------------------------------------------------------------------- /ch12/skeleton/public/weathers/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/cloudy.png -------------------------------------------------------------------------------- /ch12/skeleton/public/weathers/dreary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/dreary.png -------------------------------------------------------------------------------- /ch12/skeleton/public/weathers/night.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/night.png -------------------------------------------------------------------------------- /ch12/skeleton/public/weathers/rainy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/rainy.png -------------------------------------------------------------------------------- /ch12/skeleton/public/weathers/snowy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/snowy.png -------------------------------------------------------------------------------- /ch12/skeleton/public/weathers/sunny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/sunny.png -------------------------------------------------------------------------------- /ch12/skeleton/public/weathers/thunder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/thunder.png -------------------------------------------------------------------------------- /ch12/skeleton/public/weathers/windy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-in-Depth/react-in-depth/50486a565aa67bffa53b5bf46a8a45a6b6824116/ch12/skeleton/public/weathers/windy.png -------------------------------------------------------------------------------- /ch12/skeleton/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | module.exports = { 3 | cacheDirectory: "./node_modules/.cache/remix", 4 | ignoredRouteFiles: ["**/.*", "**/*.test.{ts,tsx}"], 5 | serverModuleFormat: "cjs", 6 | }; 7 | -------------------------------------------------------------------------------- /ch12/skeleton/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /ch13/base/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | coverage 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /ch13/base/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | base from React in Depth 8 | 9 | 10 |
    11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch13/base/src/App.jsx: -------------------------------------------------------------------------------- 1 | export default function App() { 2 | return ( 3 |
    4 |

    Check storybook, please

    5 |
    6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /ch13/base/src/library/button/index.js: -------------------------------------------------------------------------------- 1 | export { Button } from "./Button"; 2 | -------------------------------------------------------------------------------- /ch13/base/src/library/index.js: -------------------------------------------------------------------------------- 1 | export * from "./button"; 2 | -------------------------------------------------------------------------------- /ch13/base/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch13/base/vitest.setup.js: -------------------------------------------------------------------------------- 1 | import { setProjectAnnotations } from "@storybook/react"; 2 | import * as globalStorybookConfig from "./.storybook/preview"; 3 | 4 | setProjectAnnotations(globalStorybookConfig); 5 | -------------------------------------------------------------------------------- /ch13/complete/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | coverage 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /ch13/complete/src/App.jsx: -------------------------------------------------------------------------------- 1 | export default function App() { 2 | return ( 3 |
    4 |

    Check storybook, please

    5 |
    6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /ch13/complete/src/library/accordion/AccordionContext.jsx: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const AccordionContext = createContext(null); 4 | -------------------------------------------------------------------------------- /ch13/complete/src/library/accordion/index.js: -------------------------------------------------------------------------------- 1 | export { Accordion } from "./Accordion"; 2 | -------------------------------------------------------------------------------- /ch13/complete/src/library/button/index.js: -------------------------------------------------------------------------------- 1 | export { Button } from "./Button"; 2 | -------------------------------------------------------------------------------- /ch13/complete/src/library/index.js: -------------------------------------------------------------------------------- 1 | export * from "./accordion"; 2 | export * from "./button"; 3 | export * from "./switch"; 4 | export * from "./toast"; 5 | -------------------------------------------------------------------------------- /ch13/complete/src/library/switch/index.js: -------------------------------------------------------------------------------- 1 | export { Switch } from "./Switch"; 2 | -------------------------------------------------------------------------------- /ch13/complete/src/library/toast/context.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const ToastContext = createContext(null); 4 | -------------------------------------------------------------------------------- /ch13/complete/src/library/toast/index.js: -------------------------------------------------------------------------------- 1 | export { useToast } from "./useToast"; 2 | export { ToastProvider } from "./ToastProvider"; 3 | -------------------------------------------------------------------------------- /ch13/complete/src/library/toast/useToast.js: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { ToastContext } from "./context"; 3 | 4 | export function useToast() { 5 | return useContext(ToastContext); 6 | } 7 | -------------------------------------------------------------------------------- /ch13/complete/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch13/complete/vitest.setup.js: -------------------------------------------------------------------------------- 1 | import { setProjectAnnotations } from "@storybook/react"; 2 | import * as globalStorybookConfig from "./.storybook/preview"; 3 | 4 | setProjectAnnotations(globalStorybookConfig); 5 | -------------------------------------------------------------------------------- /ch14/wordle/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /ch14/wordle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | wordle from React in Depth 8 | 9 | 10 |
    11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch14/wordle/src/components/game/index.ts: -------------------------------------------------------------------------------- 1 | export { Game } from "./Game"; 2 | -------------------------------------------------------------------------------- /ch14/wordle/src/components/gamedata/index.ts: -------------------------------------------------------------------------------- 1 | export { GameDataProvider } from "./GameDataProvider"; 2 | export { useGameData } from "./useGameData"; 3 | export { useGameDialogs } from "./useGameDialogs"; 4 | -------------------------------------------------------------------------------- /ch14/wordle/src/components/gamedata/useGameData.ts: -------------------------------------------------------------------------------- 1 | import { useGameDataContext } from "./context"; 2 | 3 | export function useGameData() { 4 | const { wordInfo, profile, updateState, showResults } = 5 | useGameDataContext(); 6 | 7 | return { 8 | updateState, 9 | showResults, 10 | initialGrid: profile?.today.rows, 11 | word: wordInfo?.word || "", 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /ch14/wordle/src/components/gamedata/useGameDialogs.ts: -------------------------------------------------------------------------------- 1 | import { useGameDataContext } from "./context"; 2 | 3 | export function useGameDialogs() { 4 | const { showResults, showWelcome } = useGameDataContext(); 5 | 6 | return { 7 | showResults: () => showResults?.(), 8 | showWelcome: () => showWelcome?.(), 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /ch14/wordle/src/components/menu/index.ts: -------------------------------------------------------------------------------- 1 | export { Menu } from "./Menu"; 2 | -------------------------------------------------------------------------------- /ch14/wordle/src/components/overlay/index.ts: -------------------------------------------------------------------------------- 1 | export { OverlayProvider } from "./OverlayProvider"; 2 | export { useAlert } from "./useAlert"; 3 | export { useDialog } from "./useDialog"; 4 | -------------------------------------------------------------------------------- /ch14/wordle/src/components/overlay/useAlert.ts: -------------------------------------------------------------------------------- 1 | import { useOverlay } from "./context"; 2 | 3 | export function useAlert() { 4 | return useOverlay().alert; 5 | } 6 | -------------------------------------------------------------------------------- /ch14/wordle/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")!).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /ch14/wordle/src/styles/Provider.tsx: -------------------------------------------------------------------------------- 1 | import { ThemeProvider } from "@emotion/react"; 2 | import { PropsWithChildren } from "react"; 3 | import { theme } from "./theme"; 4 | 5 | export function StyleProvider({ children }: PropsWithChildren) { 6 | return {children}; 7 | } 8 | -------------------------------------------------------------------------------- /ch14/wordle/src/styles/emotion.d.ts: -------------------------------------------------------------------------------- 1 | import "@emotion/react"; 2 | import { EmotionTheme } from "../types"; 3 | 4 | declare module "@emotion/react" { 5 | export interface Theme extends EmotionTheme {} 6 | } 7 | -------------------------------------------------------------------------------- /ch14/wordle/src/styles/index.ts: -------------------------------------------------------------------------------- 1 | export { StyleProvider } from "./Provider"; 2 | export { theme } from "./theme"; 3 | export { GlobalStyles } from "./GlobalStyles"; 4 | -------------------------------------------------------------------------------- /ch14/wordle/src/utils/getLabel.ts: -------------------------------------------------------------------------------- 1 | import { Status } from "../types"; 2 | 3 | export function getLabel(label: string, status: Status) { 4 | if (status === Status.Unknown) { 5 | return label; 6 | } 7 | return [label, status].join(" "); 8 | } 9 | -------------------------------------------------------------------------------- /ch14/wordle/src/utils/getToday.ts: -------------------------------------------------------------------------------- 1 | export function getToday(offset = 0) { 2 | const now = new Date(); 3 | return new Date( 4 | now.getFullYear(), 5 | now.getMonth(), 6 | now.getDate() + offset 7 | ).getTime(); 8 | } 9 | 10 | export function getYesterday() { 11 | return getToday(-1); 12 | } 13 | 14 | export function getTomorrow() { 15 | return getToday(1); 16 | } 17 | -------------------------------------------------------------------------------- /ch14/wordle/src/utils/isValidWord.ts: -------------------------------------------------------------------------------- 1 | import { VALID_WORDS } from "./validWords"; 2 | 3 | export function isValidWord(word: string) { 4 | return VALID_WORDS.includes(word); 5 | } 6 | -------------------------------------------------------------------------------- /ch14/wordle/src/utils/localStorage.ts: -------------------------------------------------------------------------------- 1 | const CACHE_KEY = "JobReadyReact--Wordle"; 2 | 3 | export function getData(): T | null { 4 | const data = localStorage.getItem(CACHE_KEY); 5 | if (data) { 6 | return JSON.parse(data) as T; 7 | } 8 | return null; 9 | } 10 | 11 | export function saveData(data: T) { 12 | localStorage.setItem(CACHE_KEY, JSON.stringify(data)); 13 | } 14 | -------------------------------------------------------------------------------- /ch14/wordle/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch14/wordle/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /ch14/wordle/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from "vite"; 3 | import react from "@vitejs/plugin-react"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react()], 8 | test: { 9 | include: ["**/*.test.tsx", "**/*.test.ts"], 10 | globals: true, 11 | }, 12 | }); 13 | --------------------------------------------------------------------------------