├── .gitignore
├── README.md
├── javascript
├── .gitignore
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── App.css
│ ├── App.jsx
│ ├── App.test.jsx
│ ├── app
│ │ └── store.js
│ ├── features
│ │ └── counter
│ │ │ ├── Counter.jsx
│ │ │ ├── Counter.module.css
│ │ │ ├── counterAPI.js
│ │ │ ├── counterSlice.js
│ │ │ └── counterSlice.spec.js
│ ├── index.css
│ ├── logo.svg
│ └── main.jsx
└── vite.config.js
└── typescript
├── .gitignore
├── index.html
├── package-lock.json
├── package.json
├── src
├── App.css
├── App.tsx
├── app
│ ├── hooks.ts
│ └── store.ts
├── features
│ └── counter
│ │ ├── Counter.module.css
│ │ ├── Counter.tsx
│ │ ├── counterAPI.ts
│ │ └── counterSlice.ts
├── index.css
├── logo.svg
├── main.tsx
└── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vite-react-template-redux
2 |
3 | The (un)official Redux (JS+TS) template for [Vite](https://vitejs.dev) React.
4 |
5 | ## Usage
6 |
7 | To use a template within your project, use [degit](https://github.com/Rich-Harris/degit) to scaffold your project.
8 |
9 | ### JavaScript
10 |
11 | Use `nvh95/vite-react-template-redux/javascript` to create a project with JavaScript.
12 |
13 | ```sh
14 | npx degit nvh95/vite-react-template-redux/javascript my-app
15 |
16 | # or
17 |
18 | npx degit nvh95/vite-react-template-redux/javascript my-app --yarn
19 | ```
20 |
21 | ### TypeScript
22 |
23 | Use `nvh95/vite-react-template-redux/typescript` to create a project with TypeScript.
24 |
25 | ```sh
26 | npx degit nvh95/vite-react-template-redux/typescript my-app
27 |
28 | # or
29 |
30 | npx degit nvh95/vite-react-template-redux/typescript my-app --yarn
31 | ```
32 |
33 | For more information, please refer to:
34 |
35 | - [Getting Started](https://vitejs.dev/guide/#scaffolding-your-first-vite-project) – How to create a new app with Vite.
36 | - [User Guide](https://vitejs.dev) – How to develop apps bootstrapped with Vite.
37 |
--------------------------------------------------------------------------------
/javascript/.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 |
--------------------------------------------------------------------------------
/javascript/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/javascript/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-react-template-redux",
3 | "version": "0.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@ampproject/remapping": {
8 | "version": "2.1.2",
9 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz",
10 | "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==",
11 | "dev": true,
12 | "requires": {
13 | "@jridgewell/trace-mapping": "^0.3.0"
14 | }
15 | },
16 | "@babel/code-frame": {
17 | "version": "7.16.7",
18 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
19 | "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
20 | "dev": true,
21 | "requires": {
22 | "@babel/highlight": "^7.16.7"
23 | }
24 | },
25 | "@babel/compat-data": {
26 | "version": "7.17.7",
27 | "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz",
28 | "integrity": "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==",
29 | "dev": true
30 | },
31 | "@babel/core": {
32 | "version": "7.17.9",
33 | "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.9.tgz",
34 | "integrity": "sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw==",
35 | "dev": true,
36 | "requires": {
37 | "@ampproject/remapping": "^2.1.0",
38 | "@babel/code-frame": "^7.16.7",
39 | "@babel/generator": "^7.17.9",
40 | "@babel/helper-compilation-targets": "^7.17.7",
41 | "@babel/helper-module-transforms": "^7.17.7",
42 | "@babel/helpers": "^7.17.9",
43 | "@babel/parser": "^7.17.9",
44 | "@babel/template": "^7.16.7",
45 | "@babel/traverse": "^7.17.9",
46 | "@babel/types": "^7.17.0",
47 | "convert-source-map": "^1.7.0",
48 | "debug": "^4.1.0",
49 | "gensync": "^1.0.0-beta.2",
50 | "json5": "^2.2.1",
51 | "semver": "^6.3.0"
52 | }
53 | },
54 | "@babel/generator": {
55 | "version": "7.17.9",
56 | "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.9.tgz",
57 | "integrity": "sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ==",
58 | "dev": true,
59 | "requires": {
60 | "@babel/types": "^7.17.0",
61 | "jsesc": "^2.5.1",
62 | "source-map": "^0.5.0"
63 | }
64 | },
65 | "@babel/helper-annotate-as-pure": {
66 | "version": "7.16.7",
67 | "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz",
68 | "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==",
69 | "dev": true,
70 | "requires": {
71 | "@babel/types": "^7.16.7"
72 | }
73 | },
74 | "@babel/helper-compilation-targets": {
75 | "version": "7.17.7",
76 | "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz",
77 | "integrity": "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==",
78 | "dev": true,
79 | "requires": {
80 | "@babel/compat-data": "^7.17.7",
81 | "@babel/helper-validator-option": "^7.16.7",
82 | "browserslist": "^4.17.5",
83 | "semver": "^6.3.0"
84 | }
85 | },
86 | "@babel/helper-environment-visitor": {
87 | "version": "7.16.7",
88 | "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz",
89 | "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==",
90 | "dev": true,
91 | "requires": {
92 | "@babel/types": "^7.16.7"
93 | }
94 | },
95 | "@babel/helper-function-name": {
96 | "version": "7.17.9",
97 | "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz",
98 | "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==",
99 | "dev": true,
100 | "requires": {
101 | "@babel/template": "^7.16.7",
102 | "@babel/types": "^7.17.0"
103 | }
104 | },
105 | "@babel/helper-hoist-variables": {
106 | "version": "7.16.7",
107 | "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
108 | "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
109 | "dev": true,
110 | "requires": {
111 | "@babel/types": "^7.16.7"
112 | }
113 | },
114 | "@babel/helper-module-imports": {
115 | "version": "7.16.7",
116 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
117 | "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
118 | "dev": true,
119 | "requires": {
120 | "@babel/types": "^7.16.7"
121 | }
122 | },
123 | "@babel/helper-module-transforms": {
124 | "version": "7.17.7",
125 | "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz",
126 | "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==",
127 | "dev": true,
128 | "requires": {
129 | "@babel/helper-environment-visitor": "^7.16.7",
130 | "@babel/helper-module-imports": "^7.16.7",
131 | "@babel/helper-simple-access": "^7.17.7",
132 | "@babel/helper-split-export-declaration": "^7.16.7",
133 | "@babel/helper-validator-identifier": "^7.16.7",
134 | "@babel/template": "^7.16.7",
135 | "@babel/traverse": "^7.17.3",
136 | "@babel/types": "^7.17.0"
137 | }
138 | },
139 | "@babel/helper-plugin-utils": {
140 | "version": "7.16.7",
141 | "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz",
142 | "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==",
143 | "dev": true
144 | },
145 | "@babel/helper-simple-access": {
146 | "version": "7.17.7",
147 | "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz",
148 | "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==",
149 | "dev": true,
150 | "requires": {
151 | "@babel/types": "^7.17.0"
152 | }
153 | },
154 | "@babel/helper-split-export-declaration": {
155 | "version": "7.16.7",
156 | "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
157 | "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
158 | "dev": true,
159 | "requires": {
160 | "@babel/types": "^7.16.7"
161 | }
162 | },
163 | "@babel/helper-validator-identifier": {
164 | "version": "7.16.7",
165 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
166 | "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
167 | "dev": true
168 | },
169 | "@babel/helper-validator-option": {
170 | "version": "7.16.7",
171 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
172 | "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
173 | "dev": true
174 | },
175 | "@babel/helpers": {
176 | "version": "7.17.9",
177 | "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz",
178 | "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==",
179 | "dev": true,
180 | "requires": {
181 | "@babel/template": "^7.16.7",
182 | "@babel/traverse": "^7.17.9",
183 | "@babel/types": "^7.17.0"
184 | }
185 | },
186 | "@babel/highlight": {
187 | "version": "7.17.9",
188 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz",
189 | "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==",
190 | "dev": true,
191 | "requires": {
192 | "@babel/helper-validator-identifier": "^7.16.7",
193 | "chalk": "^2.0.0",
194 | "js-tokens": "^4.0.0"
195 | }
196 | },
197 | "@babel/parser": {
198 | "version": "7.17.9",
199 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.9.tgz",
200 | "integrity": "sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==",
201 | "dev": true
202 | },
203 | "@babel/plugin-syntax-jsx": {
204 | "version": "7.16.7",
205 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz",
206 | "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==",
207 | "dev": true,
208 | "requires": {
209 | "@babel/helper-plugin-utils": "^7.16.7"
210 | }
211 | },
212 | "@babel/plugin-transform-react-jsx": {
213 | "version": "7.17.3",
214 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz",
215 | "integrity": "sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ==",
216 | "dev": true,
217 | "requires": {
218 | "@babel/helper-annotate-as-pure": "^7.16.7",
219 | "@babel/helper-module-imports": "^7.16.7",
220 | "@babel/helper-plugin-utils": "^7.16.7",
221 | "@babel/plugin-syntax-jsx": "^7.16.7",
222 | "@babel/types": "^7.17.0"
223 | }
224 | },
225 | "@babel/plugin-transform-react-jsx-development": {
226 | "version": "7.16.7",
227 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz",
228 | "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==",
229 | "dev": true,
230 | "requires": {
231 | "@babel/plugin-transform-react-jsx": "^7.16.7"
232 | }
233 | },
234 | "@babel/plugin-transform-react-jsx-self": {
235 | "version": "7.16.7",
236 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.16.7.tgz",
237 | "integrity": "sha512-oe5VuWs7J9ilH3BCCApGoYjHoSO48vkjX2CbA5bFVhIuO2HKxA3vyF7rleA4o6/4rTDbk6r8hBW7Ul8E+UZrpA==",
238 | "dev": true,
239 | "requires": {
240 | "@babel/helper-plugin-utils": "^7.16.7"
241 | }
242 | },
243 | "@babel/plugin-transform-react-jsx-source": {
244 | "version": "7.16.7",
245 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.16.7.tgz",
246 | "integrity": "sha512-rONFiQz9vgbsnaMtQlZCjIRwhJvlrPET8TabIUK2hzlXw9B9s2Ieaxte1SCOOXMbWRHodbKixNf3BLcWVOQ8Bw==",
247 | "dev": true,
248 | "requires": {
249 | "@babel/helper-plugin-utils": "^7.16.7"
250 | }
251 | },
252 | "@babel/runtime": {
253 | "version": "7.17.9",
254 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz",
255 | "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==",
256 | "requires": {
257 | "regenerator-runtime": "^0.13.4"
258 | }
259 | },
260 | "@babel/template": {
261 | "version": "7.16.7",
262 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
263 | "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
264 | "dev": true,
265 | "requires": {
266 | "@babel/code-frame": "^7.16.7",
267 | "@babel/parser": "^7.16.7",
268 | "@babel/types": "^7.16.7"
269 | }
270 | },
271 | "@babel/traverse": {
272 | "version": "7.17.9",
273 | "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.9.tgz",
274 | "integrity": "sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw==",
275 | "dev": true,
276 | "requires": {
277 | "@babel/code-frame": "^7.16.7",
278 | "@babel/generator": "^7.17.9",
279 | "@babel/helper-environment-visitor": "^7.16.7",
280 | "@babel/helper-function-name": "^7.17.9",
281 | "@babel/helper-hoist-variables": "^7.16.7",
282 | "@babel/helper-split-export-declaration": "^7.16.7",
283 | "@babel/parser": "^7.17.9",
284 | "@babel/types": "^7.17.0",
285 | "debug": "^4.1.0",
286 | "globals": "^11.1.0"
287 | }
288 | },
289 | "@babel/types": {
290 | "version": "7.17.0",
291 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz",
292 | "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==",
293 | "dev": true,
294 | "requires": {
295 | "@babel/helper-validator-identifier": "^7.16.7",
296 | "to-fast-properties": "^2.0.0"
297 | }
298 | },
299 | "@jridgewell/resolve-uri": {
300 | "version": "3.0.6",
301 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.6.tgz",
302 | "integrity": "sha512-R7xHtBSNm+9SyvpJkdQl+qrM3Hm2fea3Ef197M3mUug+v+yR+Rhfbs7PBtcBUVnIWJ4JcAdjvij+c8hXS9p5aw==",
303 | "dev": true
304 | },
305 | "@jridgewell/sourcemap-codec": {
306 | "version": "1.4.11",
307 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz",
308 | "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==",
309 | "dev": true
310 | },
311 | "@jridgewell/trace-mapping": {
312 | "version": "0.3.9",
313 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
314 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
315 | "dev": true,
316 | "requires": {
317 | "@jridgewell/resolve-uri": "^3.0.3",
318 | "@jridgewell/sourcemap-codec": "^1.4.10"
319 | }
320 | },
321 | "@reduxjs/toolkit": {
322 | "version": "1.8.1",
323 | "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.1.tgz",
324 | "integrity": "sha512-Q6mzbTpO9nOYRnkwpDlFOAbQnd3g7zj7CtHAZWz5SzE5lcV97Tf8f3SzOO8BoPOMYBFgfZaqTUZqgGu+a0+Fng==",
325 | "requires": {
326 | "immer": "^9.0.7",
327 | "redux": "^4.1.2",
328 | "redux-thunk": "^2.4.1",
329 | "reselect": "^4.1.5"
330 | }
331 | },
332 | "@rollup/pluginutils": {
333 | "version": "4.2.1",
334 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
335 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==",
336 | "dev": true,
337 | "requires": {
338 | "estree-walker": "^2.0.1",
339 | "picomatch": "^2.2.2"
340 | }
341 | },
342 | "@types/hoist-non-react-statics": {
343 | "version": "3.3.1",
344 | "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
345 | "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
346 | "requires": {
347 | "@types/react": "*",
348 | "hoist-non-react-statics": "^3.3.0"
349 | }
350 | },
351 | "@types/prop-types": {
352 | "version": "15.7.5",
353 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
354 | "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
355 | },
356 | "@types/react": {
357 | "version": "18.0.6",
358 | "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.6.tgz",
359 | "integrity": "sha512-bPqwzJRzKtfI0mVYr5R+1o9BOE8UEXefwc1LwcBtfnaAn6OoqMhLa/91VA8aeWfDPJt1kHvYKI8RHcQybZLHHA==",
360 | "requires": {
361 | "@types/prop-types": "*",
362 | "@types/scheduler": "*",
363 | "csstype": "^3.0.2"
364 | }
365 | },
366 | "@types/react-dom": {
367 | "version": "18.0.2",
368 | "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.2.tgz",
369 | "integrity": "sha512-UxeS+Wtj5bvLRREz9tIgsK4ntCuLDo0EcAcACgw3E+9wE8ePDr9uQpq53MfcyxyIS55xJ+0B6mDS8c4qkkHLBg==",
370 | "dev": true,
371 | "requires": {
372 | "@types/react": "*"
373 | }
374 | },
375 | "@types/scheduler": {
376 | "version": "0.16.2",
377 | "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
378 | "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
379 | },
380 | "@types/use-sync-external-store": {
381 | "version": "0.0.3",
382 | "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
383 | "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
384 | },
385 | "@vitejs/plugin-react": {
386 | "version": "1.3.1",
387 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-1.3.1.tgz",
388 | "integrity": "sha512-qQS8Y2fZCjo5YmDUplEXl3yn+aueiwxB7BaoQ4nWYJYR+Ai8NXPVLlkLobVMs5+DeyFyg9Lrz6zCzdX1opcvyw==",
389 | "dev": true,
390 | "requires": {
391 | "@babel/core": "^7.17.9",
392 | "@babel/plugin-transform-react-jsx": "^7.17.3",
393 | "@babel/plugin-transform-react-jsx-development": "^7.16.7",
394 | "@babel/plugin-transform-react-jsx-self": "^7.16.7",
395 | "@babel/plugin-transform-react-jsx-source": "^7.16.7",
396 | "@rollup/pluginutils": "^4.2.0",
397 | "react-refresh": "^0.12.0",
398 | "resolve": "^1.22.0"
399 | }
400 | },
401 | "ansi-styles": {
402 | "version": "3.2.1",
403 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
404 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
405 | "dev": true,
406 | "requires": {
407 | "color-convert": "^1.9.0"
408 | }
409 | },
410 | "browserslist": {
411 | "version": "4.20.3",
412 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz",
413 | "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==",
414 | "dev": true,
415 | "requires": {
416 | "caniuse-lite": "^1.0.30001332",
417 | "electron-to-chromium": "^1.4.118",
418 | "escalade": "^3.1.1",
419 | "node-releases": "^2.0.3",
420 | "picocolors": "^1.0.0"
421 | }
422 | },
423 | "caniuse-lite": {
424 | "version": "1.0.30001332",
425 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz",
426 | "integrity": "sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==",
427 | "dev": true
428 | },
429 | "chalk": {
430 | "version": "2.4.2",
431 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
432 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
433 | "dev": true,
434 | "requires": {
435 | "ansi-styles": "^3.2.1",
436 | "escape-string-regexp": "^1.0.5",
437 | "supports-color": "^5.3.0"
438 | }
439 | },
440 | "color-convert": {
441 | "version": "1.9.3",
442 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
443 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
444 | "dev": true,
445 | "requires": {
446 | "color-name": "1.1.3"
447 | }
448 | },
449 | "color-name": {
450 | "version": "1.1.3",
451 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
452 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
453 | "dev": true
454 | },
455 | "convert-source-map": {
456 | "version": "1.8.0",
457 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
458 | "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
459 | "dev": true,
460 | "requires": {
461 | "safe-buffer": "~5.1.1"
462 | }
463 | },
464 | "csstype": {
465 | "version": "3.0.11",
466 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
467 | "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw=="
468 | },
469 | "debug": {
470 | "version": "4.3.4",
471 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
472 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
473 | "dev": true,
474 | "requires": {
475 | "ms": "2.1.2"
476 | }
477 | },
478 | "electron-to-chromium": {
479 | "version": "1.4.118",
480 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.118.tgz",
481 | "integrity": "sha512-maZIKjnYDvF7Fs35nvVcyr44UcKNwybr93Oba2n3HkKDFAtk0svERkLN/HyczJDS3Fo4wU9th9fUQd09ZLtj1w==",
482 | "dev": true
483 | },
484 | "esbuild": {
485 | "version": "0.14.38",
486 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.38.tgz",
487 | "integrity": "sha512-12fzJ0fsm7gVZX1YQ1InkOE5f9Tl7cgf6JPYXRJtPIoE0zkWAbHdPHVPPaLi9tYAcEBqheGzqLn/3RdTOyBfcA==",
488 | "dev": true,
489 | "requires": {
490 | "esbuild-android-64": "0.14.38",
491 | "esbuild-android-arm64": "0.14.38",
492 | "esbuild-darwin-64": "0.14.38",
493 | "esbuild-darwin-arm64": "0.14.38",
494 | "esbuild-freebsd-64": "0.14.38",
495 | "esbuild-freebsd-arm64": "0.14.38",
496 | "esbuild-linux-32": "0.14.38",
497 | "esbuild-linux-64": "0.14.38",
498 | "esbuild-linux-arm": "0.14.38",
499 | "esbuild-linux-arm64": "0.14.38",
500 | "esbuild-linux-mips64le": "0.14.38",
501 | "esbuild-linux-ppc64le": "0.14.38",
502 | "esbuild-linux-riscv64": "0.14.38",
503 | "esbuild-linux-s390x": "0.14.38",
504 | "esbuild-netbsd-64": "0.14.38",
505 | "esbuild-openbsd-64": "0.14.38",
506 | "esbuild-sunos-64": "0.14.38",
507 | "esbuild-windows-32": "0.14.38",
508 | "esbuild-windows-64": "0.14.38",
509 | "esbuild-windows-arm64": "0.14.38"
510 | }
511 | },
512 | "esbuild-android-64": {
513 | "version": "0.14.38",
514 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.38.tgz",
515 | "integrity": "sha512-aRFxR3scRKkbmNuGAK+Gee3+yFxkTJO/cx83Dkyzo4CnQl/2zVSurtG6+G86EQIZ+w+VYngVyK7P3HyTBKu3nw==",
516 | "dev": true,
517 | "optional": true
518 | },
519 | "esbuild-android-arm64": {
520 | "version": "0.14.38",
521 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.38.tgz",
522 | "integrity": "sha512-L2NgQRWuHFI89IIZIlpAcINy9FvBk6xFVZ7xGdOwIm8VyhX1vNCEqUJO3DPSSy945Gzdg98cxtNt8Grv1CsyhA==",
523 | "dev": true,
524 | "optional": true
525 | },
526 | "esbuild-darwin-64": {
527 | "version": "0.14.38",
528 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.38.tgz",
529 | "integrity": "sha512-5JJvgXkX87Pd1Og0u/NJuO7TSqAikAcQQ74gyJ87bqWRVeouky84ICoV4sN6VV53aTW+NE87qLdGY4QA2S7KNA==",
530 | "dev": true,
531 | "optional": true
532 | },
533 | "esbuild-darwin-arm64": {
534 | "version": "0.14.38",
535 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.38.tgz",
536 | "integrity": "sha512-eqF+OejMI3mC5Dlo9Kdq/Ilbki9sQBw3QlHW3wjLmsLh+quNfHmGMp3Ly1eWm981iGBMdbtSS9+LRvR2T8B3eQ==",
537 | "dev": true,
538 | "optional": true
539 | },
540 | "esbuild-freebsd-64": {
541 | "version": "0.14.38",
542 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.38.tgz",
543 | "integrity": "sha512-epnPbhZUt93xV5cgeY36ZxPXDsQeO55DppzsIgWM8vgiG/Rz+qYDLmh5ts3e+Ln1wA9dQ+nZmVHw+RjaW3I5Ig==",
544 | "dev": true,
545 | "optional": true
546 | },
547 | "esbuild-freebsd-arm64": {
548 | "version": "0.14.38",
549 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.38.tgz",
550 | "integrity": "sha512-/9icXUYJWherhk+y5fjPI5yNUdFPtXHQlwP7/K/zg8t8lQdHVj20SqU9/udQmeUo5pDFHMYzcEFfJqgOVeKNNQ==",
551 | "dev": true,
552 | "optional": true
553 | },
554 | "esbuild-linux-32": {
555 | "version": "0.14.38",
556 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.38.tgz",
557 | "integrity": "sha512-QfgfeNHRFvr2XeHFzP8kOZVnal3QvST3A0cgq32ZrHjSMFTdgXhMhmWdKzRXP/PKcfv3e2OW9tT9PpcjNvaq6g==",
558 | "dev": true,
559 | "optional": true
560 | },
561 | "esbuild-linux-64": {
562 | "version": "0.14.38",
563 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.38.tgz",
564 | "integrity": "sha512-uuZHNmqcs+Bj1qiW9k/HZU3FtIHmYiuxZ/6Aa+/KHb/pFKr7R3aVqvxlAudYI9Fw3St0VCPfv7QBpUITSmBR1Q==",
565 | "dev": true,
566 | "optional": true
567 | },
568 | "esbuild-linux-arm": {
569 | "version": "0.14.38",
570 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.38.tgz",
571 | "integrity": "sha512-FiFvQe8J3VKTDXG01JbvoVRXQ0x6UZwyrU4IaLBZeq39Bsbatd94Fuc3F1RGqPF5RbIWW7RvkVQjn79ejzysnA==",
572 | "dev": true,
573 | "optional": true
574 | },
575 | "esbuild-linux-arm64": {
576 | "version": "0.14.38",
577 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.38.tgz",
578 | "integrity": "sha512-HlMGZTEsBrXrivr64eZ/EO0NQM8H8DuSENRok9d+Jtvq8hOLzrxfsAT9U94K3KOGk2XgCmkaI2KD8hX7F97lvA==",
579 | "dev": true,
580 | "optional": true
581 | },
582 | "esbuild-linux-mips64le": {
583 | "version": "0.14.38",
584 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.38.tgz",
585 | "integrity": "sha512-qd1dLf2v7QBiI5wwfil9j0HG/5YMFBAmMVmdeokbNAMbcg49p25t6IlJFXAeLzogv1AvgaXRXvgFNhScYEUXGQ==",
586 | "dev": true,
587 | "optional": true
588 | },
589 | "esbuild-linux-ppc64le": {
590 | "version": "0.14.38",
591 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.38.tgz",
592 | "integrity": "sha512-mnbEm7o69gTl60jSuK+nn+pRsRHGtDPfzhrqEUXyCl7CTOCLtWN2bhK8bgsdp6J/2NyS/wHBjs1x8aBWwP2X9Q==",
593 | "dev": true,
594 | "optional": true
595 | },
596 | "esbuild-linux-riscv64": {
597 | "version": "0.14.38",
598 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.38.tgz",
599 | "integrity": "sha512-+p6YKYbuV72uikChRk14FSyNJZ4WfYkffj6Af0/Tw63/6TJX6TnIKE+6D3xtEc7DeDth1fjUOEqm+ApKFXbbVQ==",
600 | "dev": true,
601 | "optional": true
602 | },
603 | "esbuild-linux-s390x": {
604 | "version": "0.14.38",
605 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.38.tgz",
606 | "integrity": "sha512-0zUsiDkGJiMHxBQ7JDU8jbaanUY975CdOW1YDrurjrM0vWHfjv9tLQsW9GSyEb/heSK1L5gaweRjzfUVBFoybQ==",
607 | "dev": true,
608 | "optional": true
609 | },
610 | "esbuild-netbsd-64": {
611 | "version": "0.14.38",
612 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.38.tgz",
613 | "integrity": "sha512-cljBAApVwkpnJZfnRVThpRBGzCi+a+V9Ofb1fVkKhtrPLDYlHLrSYGtmnoTVWDQdU516qYI8+wOgcGZ4XIZh0Q==",
614 | "dev": true,
615 | "optional": true
616 | },
617 | "esbuild-openbsd-64": {
618 | "version": "0.14.38",
619 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.38.tgz",
620 | "integrity": "sha512-CDswYr2PWPGEPpLDUO50mL3WO/07EMjnZDNKpmaxUPsrW+kVM3LoAqr/CE8UbzugpEiflYqJsGPLirThRB18IQ==",
621 | "dev": true,
622 | "optional": true
623 | },
624 | "esbuild-sunos-64": {
625 | "version": "0.14.38",
626 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.38.tgz",
627 | "integrity": "sha512-2mfIoYW58gKcC3bck0j7lD3RZkqYA7MmujFYmSn9l6TiIcAMpuEvqksO+ntBgbLep/eyjpgdplF7b+4T9VJGOA==",
628 | "dev": true,
629 | "optional": true
630 | },
631 | "esbuild-windows-32": {
632 | "version": "0.14.38",
633 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.38.tgz",
634 | "integrity": "sha512-L2BmEeFZATAvU+FJzJiRLFUP+d9RHN+QXpgaOrs2klshoAm1AE6Us4X6fS9k33Uy5SzScn2TpcgecbqJza1Hjw==",
635 | "dev": true,
636 | "optional": true
637 | },
638 | "esbuild-windows-64": {
639 | "version": "0.14.38",
640 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.38.tgz",
641 | "integrity": "sha512-Khy4wVmebnzue8aeSXLC+6clo/hRYeNIm0DyikoEqX+3w3rcvrhzpoix0S+MF9vzh6JFskkIGD7Zx47ODJNyCw==",
642 | "dev": true,
643 | "optional": true
644 | },
645 | "esbuild-windows-arm64": {
646 | "version": "0.14.38",
647 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.38.tgz",
648 | "integrity": "sha512-k3FGCNmHBkqdJXuJszdWciAH77PukEyDsdIryEHn9cKLQFxzhT39dSumeTuggaQcXY57UlmLGIkklWZo2qzHpw==",
649 | "dev": true,
650 | "optional": true
651 | },
652 | "escalade": {
653 | "version": "3.1.1",
654 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
655 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
656 | "dev": true
657 | },
658 | "escape-string-regexp": {
659 | "version": "1.0.5",
660 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
661 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
662 | "dev": true
663 | },
664 | "estree-walker": {
665 | "version": "2.0.2",
666 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
667 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
668 | "dev": true
669 | },
670 | "fsevents": {
671 | "version": "2.3.2",
672 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
673 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
674 | "dev": true,
675 | "optional": true
676 | },
677 | "function-bind": {
678 | "version": "1.1.1",
679 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
680 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
681 | "dev": true
682 | },
683 | "gensync": {
684 | "version": "1.0.0-beta.2",
685 | "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
686 | "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
687 | "dev": true
688 | },
689 | "globals": {
690 | "version": "11.12.0",
691 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
692 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
693 | "dev": true
694 | },
695 | "has": {
696 | "version": "1.0.3",
697 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
698 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
699 | "dev": true,
700 | "requires": {
701 | "function-bind": "^1.1.1"
702 | }
703 | },
704 | "has-flag": {
705 | "version": "3.0.0",
706 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
707 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
708 | "dev": true
709 | },
710 | "hoist-non-react-statics": {
711 | "version": "3.3.2",
712 | "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
713 | "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
714 | "requires": {
715 | "react-is": "^16.7.0"
716 | },
717 | "dependencies": {
718 | "react-is": {
719 | "version": "16.13.1",
720 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
721 | "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
722 | }
723 | }
724 | },
725 | "immer": {
726 | "version": "9.0.12",
727 | "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz",
728 | "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA=="
729 | },
730 | "is-core-module": {
731 | "version": "2.9.0",
732 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz",
733 | "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==",
734 | "dev": true,
735 | "requires": {
736 | "has": "^1.0.3"
737 | }
738 | },
739 | "js-tokens": {
740 | "version": "4.0.0",
741 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
742 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
743 | },
744 | "jsesc": {
745 | "version": "2.5.2",
746 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
747 | "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
748 | "dev": true
749 | },
750 | "json5": {
751 | "version": "2.2.1",
752 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
753 | "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
754 | "dev": true
755 | },
756 | "loose-envify": {
757 | "version": "1.4.0",
758 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
759 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
760 | "requires": {
761 | "js-tokens": "^3.0.0 || ^4.0.0"
762 | }
763 | },
764 | "ms": {
765 | "version": "2.1.2",
766 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
767 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
768 | "dev": true
769 | },
770 | "nanoid": {
771 | "version": "3.3.3",
772 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
773 | "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
774 | "dev": true
775 | },
776 | "node-releases": {
777 | "version": "2.0.3",
778 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz",
779 | "integrity": "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==",
780 | "dev": true
781 | },
782 | "path-parse": {
783 | "version": "1.0.7",
784 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
785 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
786 | "dev": true
787 | },
788 | "picocolors": {
789 | "version": "1.0.0",
790 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
791 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
792 | "dev": true
793 | },
794 | "picomatch": {
795 | "version": "2.3.1",
796 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
797 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
798 | "dev": true
799 | },
800 | "postcss": {
801 | "version": "8.4.12",
802 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz",
803 | "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==",
804 | "dev": true,
805 | "requires": {
806 | "nanoid": "^3.3.1",
807 | "picocolors": "^1.0.0",
808 | "source-map-js": "^1.0.2"
809 | }
810 | },
811 | "react": {
812 | "version": "18.0.0",
813 | "resolved": "https://registry.npmjs.org/react/-/react-18.0.0.tgz",
814 | "integrity": "sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==",
815 | "requires": {
816 | "loose-envify": "^1.1.0"
817 | }
818 | },
819 | "react-dom": {
820 | "version": "18.0.0",
821 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.0.0.tgz",
822 | "integrity": "sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw==",
823 | "requires": {
824 | "loose-envify": "^1.1.0",
825 | "scheduler": "^0.21.0"
826 | }
827 | },
828 | "react-is": {
829 | "version": "18.0.0",
830 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.0.0.tgz",
831 | "integrity": "sha512-yUcBYdBBbo3QiPsgYDcfQcIkGZHfxOaoE6HLSnr1sPzMhdyxusbfKOSUbSd/ocGi32dxcj366PsTj+5oggeKKw=="
832 | },
833 | "react-redux": {
834 | "version": "8.0.1",
835 | "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.1.tgz",
836 | "integrity": "sha512-LMZMsPY4DYdZfLJgd7i79n5Kps5N9XVLCJJeWAaPYTV+Eah2zTuBjTxKtNEbjiyitbq80/eIkm55CYSLqAub3w==",
837 | "requires": {
838 | "@babel/runtime": "^7.12.1",
839 | "@types/hoist-non-react-statics": "^3.3.1",
840 | "@types/use-sync-external-store": "^0.0.3",
841 | "hoist-non-react-statics": "^3.3.2",
842 | "react-is": "^18.0.0",
843 | "use-sync-external-store": "^1.0.0"
844 | }
845 | },
846 | "react-refresh": {
847 | "version": "0.12.0",
848 | "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.12.0.tgz",
849 | "integrity": "sha512-suLIhrU2IHKL5JEKR/fAwJv7bbeq4kJ+pJopf77jHwuR+HmJS/HbrPIGsTBUVfw7tXPOmYv7UJ7PCaN49e8x4A==",
850 | "dev": true
851 | },
852 | "redux": {
853 | "version": "4.2.0",
854 | "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz",
855 | "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==",
856 | "requires": {
857 | "@babel/runtime": "^7.9.2"
858 | }
859 | },
860 | "redux-thunk": {
861 | "version": "2.4.1",
862 | "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
863 | "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q=="
864 | },
865 | "regenerator-runtime": {
866 | "version": "0.13.9",
867 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
868 | "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
869 | },
870 | "reselect": {
871 | "version": "4.1.5",
872 | "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz",
873 | "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ=="
874 | },
875 | "resolve": {
876 | "version": "1.22.0",
877 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
878 | "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
879 | "dev": true,
880 | "requires": {
881 | "is-core-module": "^2.8.1",
882 | "path-parse": "^1.0.7",
883 | "supports-preserve-symlinks-flag": "^1.0.0"
884 | }
885 | },
886 | "rollup": {
887 | "version": "2.70.2",
888 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.70.2.tgz",
889 | "integrity": "sha512-EitogNZnfku65I1DD5Mxe8JYRUCy0hkK5X84IlDtUs+O6JRMpRciXTzyCUuX11b5L5pvjH+OmFXiQ3XjabcXgg==",
890 | "dev": true,
891 | "requires": {
892 | "fsevents": "~2.3.2"
893 | }
894 | },
895 | "safe-buffer": {
896 | "version": "5.1.2",
897 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
898 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
899 | "dev": true
900 | },
901 | "scheduler": {
902 | "version": "0.21.0",
903 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz",
904 | "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==",
905 | "requires": {
906 | "loose-envify": "^1.1.0"
907 | }
908 | },
909 | "semver": {
910 | "version": "6.3.0",
911 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
912 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
913 | "dev": true
914 | },
915 | "source-map": {
916 | "version": "0.5.7",
917 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
918 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
919 | "dev": true
920 | },
921 | "source-map-js": {
922 | "version": "1.0.2",
923 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
924 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
925 | "dev": true
926 | },
927 | "supports-color": {
928 | "version": "5.5.0",
929 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
930 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
931 | "dev": true,
932 | "requires": {
933 | "has-flag": "^3.0.0"
934 | }
935 | },
936 | "supports-preserve-symlinks-flag": {
937 | "version": "1.0.0",
938 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
939 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
940 | "dev": true
941 | },
942 | "to-fast-properties": {
943 | "version": "2.0.0",
944 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
945 | "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
946 | "dev": true
947 | },
948 | "use-sync-external-store": {
949 | "version": "1.0.0",
950 | "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.0.0.tgz",
951 | "integrity": "sha512-AFVsxg5GkFg8GDcxnl+Z0lMAz9rE8DGJCc28qnBuQF7lac57B5smLcT37aXpXIIPz75rW4g3eXHPjhHwdGskOw=="
952 | },
953 | "vite": {
954 | "version": "2.9.5",
955 | "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.5.tgz",
956 | "integrity": "sha512-dvMN64X2YEQgSXF1lYabKXw3BbN6e+BL67+P3Vy4MacnY+UzT1AfkHiioFSi9+uiDUiaDy7Ax/LQqivk6orilg==",
957 | "dev": true,
958 | "requires": {
959 | "esbuild": "^0.14.27",
960 | "fsevents": "~2.3.2",
961 | "postcss": "^8.4.12",
962 | "resolve": "^1.22.0",
963 | "rollup": "^2.59.0"
964 | }
965 | }
966 | }
967 | }
968 |
--------------------------------------------------------------------------------
/javascript/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-react-template-redux",
3 | "private": true,
4 | "version": "0.0.0",
5 | "scripts": {
6 | "dev": "vite",
7 | "build": "vite build",
8 | "preview": "vite preview"
9 | },
10 | "dependencies": {
11 | "@reduxjs/toolkit": "^1.8.1",
12 | "react": "^18.0.0",
13 | "react-dom": "^18.0.0",
14 | "react-redux": "^8.0.1"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.0.0",
18 | "@types/react-dom": "^18.0.0",
19 | "@vitejs/plugin-react": "^1.3.0",
20 | "vite": "^2.9.5"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/javascript/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-float infinite 3s ease-in-out;
13 | }
14 | }
15 |
16 | .App-header {
17 | min-height: 100vh;
18 | display: flex;
19 | flex-direction: column;
20 | align-items: center;
21 | justify-content: center;
22 | font-size: calc(10px + 2vmin);
23 | }
24 |
25 | .App-link {
26 | color: rgb(112, 76, 182);
27 | }
28 |
29 | @keyframes App-logo-float {
30 | 0% {
31 | transform: translateY(0);
32 | }
33 | 50% {
34 | transform: translateY(10px);
35 | }
36 | 100% {
37 | transform: translateY(0px);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/javascript/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import logo from "./logo.svg";
3 | import { Counter } from "./features/counter/Counter";
4 | import "./App.css";
5 |
6 | function App() {
7 | return (
8 |
55 | );
56 | }
57 |
58 | export default App;
59 |
--------------------------------------------------------------------------------
/javascript/src/App.test.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "@testing-library/react";
3 | import { Provider } from "react-redux";
4 | import { store } from "./app/store";
5 | import App from "./App";
6 |
7 | test("renders learn react link", () => {
8 | const { getByText } = render(
9 |
10 |
11 |
12 | );
13 |
14 | expect(getByText(/learn/i)).toBeInTheDocument();
15 | });
16 |
--------------------------------------------------------------------------------
/javascript/src/app/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from "@reduxjs/toolkit";
2 | import counterReducer from "../features/counter/counterSlice";
3 |
4 | export const store = configureStore({
5 | reducer: {
6 | counter: counterReducer,
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/javascript/src/features/counter/Counter.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { useSelector, useDispatch } from "react-redux";
3 | import {
4 | decrement,
5 | increment,
6 | incrementByAmount,
7 | incrementAsync,
8 | incrementIfOdd,
9 | selectCount,
10 | } from "./counterSlice";
11 | import styles from "./Counter.module.css";
12 |
13 | export function Counter() {
14 | const count = useSelector(selectCount);
15 | const dispatch = useDispatch();
16 | const [incrementAmount, setIncrementAmount] = useState("2");
17 |
18 | const incrementValue = Number(incrementAmount) || 0;
19 |
20 | return (
21 |
22 |
23 |
30 | {count}
31 |
38 |
39 |
40 | setIncrementAmount(e.target.value)}
45 | />
46 |
52 |
58 |
64 |
65 |
66 | );
67 | }
68 |
--------------------------------------------------------------------------------
/javascript/src/features/counter/Counter.module.css:
--------------------------------------------------------------------------------
1 | .row {
2 | display: flex;
3 | align-items: center;
4 | justify-content: center;
5 | }
6 |
7 | .row > button {
8 | margin-left: 4px;
9 | margin-right: 8px;
10 | }
11 | .row:not(:last-child) {
12 | margin-bottom: 16px;
13 | }
14 |
15 | .value {
16 | font-size: 78px;
17 | padding-left: 16px;
18 | padding-right: 16px;
19 | margin-top: 2px;
20 | font-family: "Courier New", Courier, monospace;
21 | }
22 |
23 | .button {
24 | appearance: none;
25 | background: none;
26 | font-size: 32px;
27 | padding-left: 12px;
28 | padding-right: 12px;
29 | outline: none;
30 | border: 2px solid transparent;
31 | color: rgb(112, 76, 182);
32 | padding-bottom: 4px;
33 | cursor: pointer;
34 | background-color: rgba(112, 76, 182, 0.1);
35 | border-radius: 2px;
36 | transition: all 0.15s;
37 | }
38 |
39 | .textbox {
40 | font-size: 32px;
41 | padding: 2px;
42 | width: 64px;
43 | text-align: center;
44 | margin-right: 4px;
45 | }
46 |
47 | .button:hover,
48 | .button:focus {
49 | border: 2px solid rgba(112, 76, 182, 0.4);
50 | }
51 |
52 | .button:active {
53 | background-color: rgba(112, 76, 182, 0.2);
54 | }
55 |
56 | .asyncButton {
57 | composes: button;
58 | position: relative;
59 | }
60 |
61 | .asyncButton:after {
62 | content: "";
63 | background-color: rgba(112, 76, 182, 0.15);
64 | display: block;
65 | position: absolute;
66 | width: 100%;
67 | height: 100%;
68 | left: 0;
69 | top: 0;
70 | opacity: 0;
71 | transition: width 1s linear, opacity 0.5s ease 1s;
72 | }
73 |
74 | .asyncButton:active:after {
75 | width: 0%;
76 | opacity: 1;
77 | transition: 0s;
78 | }
79 |
--------------------------------------------------------------------------------
/javascript/src/features/counter/counterAPI.js:
--------------------------------------------------------------------------------
1 | // A mock function to mimic making an async request for data
2 | export function fetchCount(amount = 1) {
3 | return new Promise((resolve) =>
4 | setTimeout(() => resolve({ data: amount }), 500)
5 | );
6 | }
7 |
--------------------------------------------------------------------------------
/javascript/src/features/counter/counterSlice.js:
--------------------------------------------------------------------------------
1 | import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
2 | import { fetchCount } from "./counterAPI";
3 |
4 | const initialState = {
5 | value: 0,
6 | status: "idle",
7 | };
8 |
9 | // The function below is called a thunk and allows us to perform async logic. It
10 | // can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
11 | // will call the thunk with the `dispatch` function as the first argument. Async
12 | // code can then be executed and other actions can be dispatched. Thunks are
13 | // typically used to make async requests.
14 | export const incrementAsync = createAsyncThunk(
15 | "counter/fetchCount",
16 | async (amount) => {
17 | const response = await fetchCount(amount);
18 | // The value we return becomes the `fulfilled` action payload
19 | return response.data;
20 | }
21 | );
22 |
23 | export const counterSlice = createSlice({
24 | name: "counter",
25 | initialState,
26 | // The `reducers` field lets us define reducers and generate associated actions
27 | reducers: {
28 | increment: (state) => {
29 | // Redux Toolkit allows us to write "mutating" logic in reducers. It
30 | // doesn't actually mutate the state because it uses the Immer library,
31 | // which detects changes to a "draft state" and produces a brand new
32 | // immutable state based off those changes
33 | state.value += 1;
34 | },
35 | decrement: (state) => {
36 | state.value -= 1;
37 | },
38 | // Use the PayloadAction type to declare the contents of `action.payload`
39 | incrementByAmount: (state, action) => {
40 | state.value += action.payload;
41 | },
42 | },
43 | // The `extraReducers` field lets the slice handle actions defined elsewhere,
44 | // including actions generated by createAsyncThunk or in other slices.
45 | extraReducers: (builder) => {
46 | builder
47 | .addCase(incrementAsync.pending, (state) => {
48 | state.status = "loading";
49 | })
50 | .addCase(incrementAsync.fulfilled, (state, action) => {
51 | state.status = "idle";
52 | state.value += action.payload;
53 | });
54 | },
55 | });
56 |
57 | export const { increment, decrement, incrementByAmount } = counterSlice.actions;
58 |
59 | // The function below is called a selector and allows us to select a value from
60 | // the state. Selectors can also be defined inline where they're used instead of
61 | // in the slice file. For example: `useSelector((state: RootState) => state.counter.value)`
62 | export const selectCount = (state) => state.counter.value;
63 |
64 | // We can also write thunks by hand, which may contain both sync and async logic.
65 | // Here's an example of conditionally dispatching actions based on current state.
66 | export const incrementIfOdd = (amount) => (dispatch, getState) => {
67 | const currentValue = selectCount(getState());
68 | if (currentValue % 2 === 1) {
69 | dispatch(incrementByAmount(amount));
70 | }
71 | };
72 |
73 | export default counterSlice.reducer;
74 |
--------------------------------------------------------------------------------
/javascript/src/features/counter/counterSlice.spec.js:
--------------------------------------------------------------------------------
1 | import counterReducer, {
2 | increment,
3 | decrement,
4 | incrementByAmount,
5 | } from "./counterSlice";
6 |
7 | describe("counter reducer", () => {
8 | const initialState = {
9 | value: 3,
10 | status: "idle",
11 | };
12 | it("should handle initial state", () => {
13 | expect(counterReducer(undefined, { type: "unknown" })).toEqual({
14 | value: 0,
15 | status: "idle",
16 | });
17 | });
18 |
19 | it("should handle increment", () => {
20 | const actual = counterReducer(initialState, increment());
21 | expect(actual.value).toEqual(4);
22 | });
23 |
24 | it("should handle decrement", () => {
25 | const actual = counterReducer(initialState, decrement());
26 | expect(actual.value).toEqual(2);
27 | });
28 |
29 | it("should handle incrementByAmount", () => {
30 | const actual = counterReducer(initialState, incrementByAmount(2));
31 | expect(actual.value).toEqual(5);
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/javascript/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/javascript/src/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/javascript/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import { Provider } from "react-redux";
4 | import { store } from "./app/store";
5 | import App from "./App";
6 | import "./index.css";
7 |
8 | ReactDOM.createRoot(document.getElementById("root")).render(
9 |
10 |
11 |
12 |
13 |
14 | );
15 |
--------------------------------------------------------------------------------
/javascript/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 |
--------------------------------------------------------------------------------
/typescript/.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 |
--------------------------------------------------------------------------------
/typescript/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/typescript/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-react-template-redux",
3 | "version": "0.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@ampproject/remapping": {
8 | "version": "2.1.2",
9 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz",
10 | "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==",
11 | "dev": true,
12 | "requires": {
13 | "@jridgewell/trace-mapping": "^0.3.0"
14 | }
15 | },
16 | "@babel/code-frame": {
17 | "version": "7.16.7",
18 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
19 | "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
20 | "dev": true,
21 | "requires": {
22 | "@babel/highlight": "^7.16.7"
23 | }
24 | },
25 | "@babel/compat-data": {
26 | "version": "7.17.7",
27 | "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz",
28 | "integrity": "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==",
29 | "dev": true
30 | },
31 | "@babel/core": {
32 | "version": "7.17.9",
33 | "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.9.tgz",
34 | "integrity": "sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw==",
35 | "dev": true,
36 | "requires": {
37 | "@ampproject/remapping": "^2.1.0",
38 | "@babel/code-frame": "^7.16.7",
39 | "@babel/generator": "^7.17.9",
40 | "@babel/helper-compilation-targets": "^7.17.7",
41 | "@babel/helper-module-transforms": "^7.17.7",
42 | "@babel/helpers": "^7.17.9",
43 | "@babel/parser": "^7.17.9",
44 | "@babel/template": "^7.16.7",
45 | "@babel/traverse": "^7.17.9",
46 | "@babel/types": "^7.17.0",
47 | "convert-source-map": "^1.7.0",
48 | "debug": "^4.1.0",
49 | "gensync": "^1.0.0-beta.2",
50 | "json5": "^2.2.1",
51 | "semver": "^6.3.0"
52 | }
53 | },
54 | "@babel/generator": {
55 | "version": "7.17.9",
56 | "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.9.tgz",
57 | "integrity": "sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ==",
58 | "dev": true,
59 | "requires": {
60 | "@babel/types": "^7.17.0",
61 | "jsesc": "^2.5.1",
62 | "source-map": "^0.5.0"
63 | }
64 | },
65 | "@babel/helper-annotate-as-pure": {
66 | "version": "7.16.7",
67 | "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz",
68 | "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==",
69 | "dev": true,
70 | "requires": {
71 | "@babel/types": "^7.16.7"
72 | }
73 | },
74 | "@babel/helper-compilation-targets": {
75 | "version": "7.17.7",
76 | "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz",
77 | "integrity": "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==",
78 | "dev": true,
79 | "requires": {
80 | "@babel/compat-data": "^7.17.7",
81 | "@babel/helper-validator-option": "^7.16.7",
82 | "browserslist": "^4.17.5",
83 | "semver": "^6.3.0"
84 | }
85 | },
86 | "@babel/helper-environment-visitor": {
87 | "version": "7.16.7",
88 | "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz",
89 | "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==",
90 | "dev": true,
91 | "requires": {
92 | "@babel/types": "^7.16.7"
93 | }
94 | },
95 | "@babel/helper-function-name": {
96 | "version": "7.17.9",
97 | "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz",
98 | "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==",
99 | "dev": true,
100 | "requires": {
101 | "@babel/template": "^7.16.7",
102 | "@babel/types": "^7.17.0"
103 | }
104 | },
105 | "@babel/helper-hoist-variables": {
106 | "version": "7.16.7",
107 | "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
108 | "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
109 | "dev": true,
110 | "requires": {
111 | "@babel/types": "^7.16.7"
112 | }
113 | },
114 | "@babel/helper-module-imports": {
115 | "version": "7.16.7",
116 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
117 | "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
118 | "dev": true,
119 | "requires": {
120 | "@babel/types": "^7.16.7"
121 | }
122 | },
123 | "@babel/helper-module-transforms": {
124 | "version": "7.17.7",
125 | "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz",
126 | "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==",
127 | "dev": true,
128 | "requires": {
129 | "@babel/helper-environment-visitor": "^7.16.7",
130 | "@babel/helper-module-imports": "^7.16.7",
131 | "@babel/helper-simple-access": "^7.17.7",
132 | "@babel/helper-split-export-declaration": "^7.16.7",
133 | "@babel/helper-validator-identifier": "^7.16.7",
134 | "@babel/template": "^7.16.7",
135 | "@babel/traverse": "^7.17.3",
136 | "@babel/types": "^7.17.0"
137 | }
138 | },
139 | "@babel/helper-plugin-utils": {
140 | "version": "7.16.7",
141 | "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz",
142 | "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==",
143 | "dev": true
144 | },
145 | "@babel/helper-simple-access": {
146 | "version": "7.17.7",
147 | "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz",
148 | "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==",
149 | "dev": true,
150 | "requires": {
151 | "@babel/types": "^7.17.0"
152 | }
153 | },
154 | "@babel/helper-split-export-declaration": {
155 | "version": "7.16.7",
156 | "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
157 | "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
158 | "dev": true,
159 | "requires": {
160 | "@babel/types": "^7.16.7"
161 | }
162 | },
163 | "@babel/helper-validator-identifier": {
164 | "version": "7.16.7",
165 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
166 | "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
167 | "dev": true
168 | },
169 | "@babel/helper-validator-option": {
170 | "version": "7.16.7",
171 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
172 | "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
173 | "dev": true
174 | },
175 | "@babel/helpers": {
176 | "version": "7.17.9",
177 | "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz",
178 | "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==",
179 | "dev": true,
180 | "requires": {
181 | "@babel/template": "^7.16.7",
182 | "@babel/traverse": "^7.17.9",
183 | "@babel/types": "^7.17.0"
184 | }
185 | },
186 | "@babel/highlight": {
187 | "version": "7.17.9",
188 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz",
189 | "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==",
190 | "dev": true,
191 | "requires": {
192 | "@babel/helper-validator-identifier": "^7.16.7",
193 | "chalk": "^2.0.0",
194 | "js-tokens": "^4.0.0"
195 | }
196 | },
197 | "@babel/parser": {
198 | "version": "7.17.9",
199 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.9.tgz",
200 | "integrity": "sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==",
201 | "dev": true
202 | },
203 | "@babel/plugin-syntax-jsx": {
204 | "version": "7.16.7",
205 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz",
206 | "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==",
207 | "dev": true,
208 | "requires": {
209 | "@babel/helper-plugin-utils": "^7.16.7"
210 | }
211 | },
212 | "@babel/plugin-transform-react-jsx": {
213 | "version": "7.17.3",
214 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz",
215 | "integrity": "sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ==",
216 | "dev": true,
217 | "requires": {
218 | "@babel/helper-annotate-as-pure": "^7.16.7",
219 | "@babel/helper-module-imports": "^7.16.7",
220 | "@babel/helper-plugin-utils": "^7.16.7",
221 | "@babel/plugin-syntax-jsx": "^7.16.7",
222 | "@babel/types": "^7.17.0"
223 | }
224 | },
225 | "@babel/plugin-transform-react-jsx-development": {
226 | "version": "7.16.7",
227 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz",
228 | "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==",
229 | "dev": true,
230 | "requires": {
231 | "@babel/plugin-transform-react-jsx": "^7.16.7"
232 | }
233 | },
234 | "@babel/plugin-transform-react-jsx-self": {
235 | "version": "7.16.7",
236 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.16.7.tgz",
237 | "integrity": "sha512-oe5VuWs7J9ilH3BCCApGoYjHoSO48vkjX2CbA5bFVhIuO2HKxA3vyF7rleA4o6/4rTDbk6r8hBW7Ul8E+UZrpA==",
238 | "dev": true,
239 | "requires": {
240 | "@babel/helper-plugin-utils": "^7.16.7"
241 | }
242 | },
243 | "@babel/plugin-transform-react-jsx-source": {
244 | "version": "7.16.7",
245 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.16.7.tgz",
246 | "integrity": "sha512-rONFiQz9vgbsnaMtQlZCjIRwhJvlrPET8TabIUK2hzlXw9B9s2Ieaxte1SCOOXMbWRHodbKixNf3BLcWVOQ8Bw==",
247 | "dev": true,
248 | "requires": {
249 | "@babel/helper-plugin-utils": "^7.16.7"
250 | }
251 | },
252 | "@babel/runtime": {
253 | "version": "7.17.9",
254 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz",
255 | "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==",
256 | "requires": {
257 | "regenerator-runtime": "^0.13.4"
258 | }
259 | },
260 | "@babel/template": {
261 | "version": "7.16.7",
262 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
263 | "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
264 | "dev": true,
265 | "requires": {
266 | "@babel/code-frame": "^7.16.7",
267 | "@babel/parser": "^7.16.7",
268 | "@babel/types": "^7.16.7"
269 | }
270 | },
271 | "@babel/traverse": {
272 | "version": "7.17.9",
273 | "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.9.tgz",
274 | "integrity": "sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw==",
275 | "dev": true,
276 | "requires": {
277 | "@babel/code-frame": "^7.16.7",
278 | "@babel/generator": "^7.17.9",
279 | "@babel/helper-environment-visitor": "^7.16.7",
280 | "@babel/helper-function-name": "^7.17.9",
281 | "@babel/helper-hoist-variables": "^7.16.7",
282 | "@babel/helper-split-export-declaration": "^7.16.7",
283 | "@babel/parser": "^7.17.9",
284 | "@babel/types": "^7.17.0",
285 | "debug": "^4.1.0",
286 | "globals": "^11.1.0"
287 | }
288 | },
289 | "@babel/types": {
290 | "version": "7.17.0",
291 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz",
292 | "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==",
293 | "dev": true,
294 | "requires": {
295 | "@babel/helper-validator-identifier": "^7.16.7",
296 | "to-fast-properties": "^2.0.0"
297 | }
298 | },
299 | "@jridgewell/resolve-uri": {
300 | "version": "3.0.6",
301 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.6.tgz",
302 | "integrity": "sha512-R7xHtBSNm+9SyvpJkdQl+qrM3Hm2fea3Ef197M3mUug+v+yR+Rhfbs7PBtcBUVnIWJ4JcAdjvij+c8hXS9p5aw==",
303 | "dev": true
304 | },
305 | "@jridgewell/sourcemap-codec": {
306 | "version": "1.4.11",
307 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz",
308 | "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==",
309 | "dev": true
310 | },
311 | "@jridgewell/trace-mapping": {
312 | "version": "0.3.9",
313 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
314 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
315 | "dev": true,
316 | "requires": {
317 | "@jridgewell/resolve-uri": "^3.0.3",
318 | "@jridgewell/sourcemap-codec": "^1.4.10"
319 | }
320 | },
321 | "@reduxjs/toolkit": {
322 | "version": "1.8.1",
323 | "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.1.tgz",
324 | "integrity": "sha512-Q6mzbTpO9nOYRnkwpDlFOAbQnd3g7zj7CtHAZWz5SzE5lcV97Tf8f3SzOO8BoPOMYBFgfZaqTUZqgGu+a0+Fng==",
325 | "requires": {
326 | "immer": "^9.0.7",
327 | "redux": "^4.1.2",
328 | "redux-thunk": "^2.4.1",
329 | "reselect": "^4.1.5"
330 | }
331 | },
332 | "@rollup/pluginutils": {
333 | "version": "4.2.1",
334 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
335 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==",
336 | "dev": true,
337 | "requires": {
338 | "estree-walker": "^2.0.1",
339 | "picomatch": "^2.2.2"
340 | }
341 | },
342 | "@types/hoist-non-react-statics": {
343 | "version": "3.3.1",
344 | "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
345 | "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
346 | "requires": {
347 | "@types/react": "*",
348 | "hoist-non-react-statics": "^3.3.0"
349 | }
350 | },
351 | "@types/prop-types": {
352 | "version": "15.7.5",
353 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
354 | "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
355 | },
356 | "@types/react": {
357 | "version": "18.0.6",
358 | "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.6.tgz",
359 | "integrity": "sha512-bPqwzJRzKtfI0mVYr5R+1o9BOE8UEXefwc1LwcBtfnaAn6OoqMhLa/91VA8aeWfDPJt1kHvYKI8RHcQybZLHHA==",
360 | "requires": {
361 | "@types/prop-types": "*",
362 | "@types/scheduler": "*",
363 | "csstype": "^3.0.2"
364 | }
365 | },
366 | "@types/react-dom": {
367 | "version": "18.0.2",
368 | "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.2.tgz",
369 | "integrity": "sha512-UxeS+Wtj5bvLRREz9tIgsK4ntCuLDo0EcAcACgw3E+9wE8ePDr9uQpq53MfcyxyIS55xJ+0B6mDS8c4qkkHLBg==",
370 | "dev": true,
371 | "requires": {
372 | "@types/react": "*"
373 | }
374 | },
375 | "@types/scheduler": {
376 | "version": "0.16.2",
377 | "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
378 | "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
379 | },
380 | "@types/use-sync-external-store": {
381 | "version": "0.0.3",
382 | "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
383 | "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
384 | },
385 | "@vitejs/plugin-react": {
386 | "version": "1.3.1",
387 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-1.3.1.tgz",
388 | "integrity": "sha512-qQS8Y2fZCjo5YmDUplEXl3yn+aueiwxB7BaoQ4nWYJYR+Ai8NXPVLlkLobVMs5+DeyFyg9Lrz6zCzdX1opcvyw==",
389 | "dev": true,
390 | "requires": {
391 | "@babel/core": "^7.17.9",
392 | "@babel/plugin-transform-react-jsx": "^7.17.3",
393 | "@babel/plugin-transform-react-jsx-development": "^7.16.7",
394 | "@babel/plugin-transform-react-jsx-self": "^7.16.7",
395 | "@babel/plugin-transform-react-jsx-source": "^7.16.7",
396 | "@rollup/pluginutils": "^4.2.0",
397 | "react-refresh": "^0.12.0",
398 | "resolve": "^1.22.0"
399 | }
400 | },
401 | "ansi-styles": {
402 | "version": "3.2.1",
403 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
404 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
405 | "dev": true,
406 | "requires": {
407 | "color-convert": "^1.9.0"
408 | }
409 | },
410 | "browserslist": {
411 | "version": "4.20.3",
412 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz",
413 | "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==",
414 | "dev": true,
415 | "requires": {
416 | "caniuse-lite": "^1.0.30001332",
417 | "electron-to-chromium": "^1.4.118",
418 | "escalade": "^3.1.1",
419 | "node-releases": "^2.0.3",
420 | "picocolors": "^1.0.0"
421 | }
422 | },
423 | "caniuse-lite": {
424 | "version": "1.0.30001332",
425 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz",
426 | "integrity": "sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==",
427 | "dev": true
428 | },
429 | "chalk": {
430 | "version": "2.4.2",
431 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
432 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
433 | "dev": true,
434 | "requires": {
435 | "ansi-styles": "^3.2.1",
436 | "escape-string-regexp": "^1.0.5",
437 | "supports-color": "^5.3.0"
438 | }
439 | },
440 | "color-convert": {
441 | "version": "1.9.3",
442 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
443 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
444 | "dev": true,
445 | "requires": {
446 | "color-name": "1.1.3"
447 | }
448 | },
449 | "color-name": {
450 | "version": "1.1.3",
451 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
452 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
453 | "dev": true
454 | },
455 | "convert-source-map": {
456 | "version": "1.8.0",
457 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz",
458 | "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==",
459 | "dev": true,
460 | "requires": {
461 | "safe-buffer": "~5.1.1"
462 | }
463 | },
464 | "csstype": {
465 | "version": "3.0.11",
466 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
467 | "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw=="
468 | },
469 | "debug": {
470 | "version": "4.3.4",
471 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
472 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
473 | "dev": true,
474 | "requires": {
475 | "ms": "2.1.2"
476 | }
477 | },
478 | "electron-to-chromium": {
479 | "version": "1.4.118",
480 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.118.tgz",
481 | "integrity": "sha512-maZIKjnYDvF7Fs35nvVcyr44UcKNwybr93Oba2n3HkKDFAtk0svERkLN/HyczJDS3Fo4wU9th9fUQd09ZLtj1w==",
482 | "dev": true
483 | },
484 | "esbuild": {
485 | "version": "0.14.38",
486 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.38.tgz",
487 | "integrity": "sha512-12fzJ0fsm7gVZX1YQ1InkOE5f9Tl7cgf6JPYXRJtPIoE0zkWAbHdPHVPPaLi9tYAcEBqheGzqLn/3RdTOyBfcA==",
488 | "dev": true,
489 | "requires": {
490 | "esbuild-android-64": "0.14.38",
491 | "esbuild-android-arm64": "0.14.38",
492 | "esbuild-darwin-64": "0.14.38",
493 | "esbuild-darwin-arm64": "0.14.38",
494 | "esbuild-freebsd-64": "0.14.38",
495 | "esbuild-freebsd-arm64": "0.14.38",
496 | "esbuild-linux-32": "0.14.38",
497 | "esbuild-linux-64": "0.14.38",
498 | "esbuild-linux-arm": "0.14.38",
499 | "esbuild-linux-arm64": "0.14.38",
500 | "esbuild-linux-mips64le": "0.14.38",
501 | "esbuild-linux-ppc64le": "0.14.38",
502 | "esbuild-linux-riscv64": "0.14.38",
503 | "esbuild-linux-s390x": "0.14.38",
504 | "esbuild-netbsd-64": "0.14.38",
505 | "esbuild-openbsd-64": "0.14.38",
506 | "esbuild-sunos-64": "0.14.38",
507 | "esbuild-windows-32": "0.14.38",
508 | "esbuild-windows-64": "0.14.38",
509 | "esbuild-windows-arm64": "0.14.38"
510 | }
511 | },
512 | "esbuild-android-64": {
513 | "version": "0.14.38",
514 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.38.tgz",
515 | "integrity": "sha512-aRFxR3scRKkbmNuGAK+Gee3+yFxkTJO/cx83Dkyzo4CnQl/2zVSurtG6+G86EQIZ+w+VYngVyK7P3HyTBKu3nw==",
516 | "dev": true,
517 | "optional": true
518 | },
519 | "esbuild-android-arm64": {
520 | "version": "0.14.38",
521 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.38.tgz",
522 | "integrity": "sha512-L2NgQRWuHFI89IIZIlpAcINy9FvBk6xFVZ7xGdOwIm8VyhX1vNCEqUJO3DPSSy945Gzdg98cxtNt8Grv1CsyhA==",
523 | "dev": true,
524 | "optional": true
525 | },
526 | "esbuild-darwin-64": {
527 | "version": "0.14.38",
528 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.38.tgz",
529 | "integrity": "sha512-5JJvgXkX87Pd1Og0u/NJuO7TSqAikAcQQ74gyJ87bqWRVeouky84ICoV4sN6VV53aTW+NE87qLdGY4QA2S7KNA==",
530 | "dev": true,
531 | "optional": true
532 | },
533 | "esbuild-darwin-arm64": {
534 | "version": "0.14.38",
535 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.38.tgz",
536 | "integrity": "sha512-eqF+OejMI3mC5Dlo9Kdq/Ilbki9sQBw3QlHW3wjLmsLh+quNfHmGMp3Ly1eWm981iGBMdbtSS9+LRvR2T8B3eQ==",
537 | "dev": true,
538 | "optional": true
539 | },
540 | "esbuild-freebsd-64": {
541 | "version": "0.14.38",
542 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.38.tgz",
543 | "integrity": "sha512-epnPbhZUt93xV5cgeY36ZxPXDsQeO55DppzsIgWM8vgiG/Rz+qYDLmh5ts3e+Ln1wA9dQ+nZmVHw+RjaW3I5Ig==",
544 | "dev": true,
545 | "optional": true
546 | },
547 | "esbuild-freebsd-arm64": {
548 | "version": "0.14.38",
549 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.38.tgz",
550 | "integrity": "sha512-/9icXUYJWherhk+y5fjPI5yNUdFPtXHQlwP7/K/zg8t8lQdHVj20SqU9/udQmeUo5pDFHMYzcEFfJqgOVeKNNQ==",
551 | "dev": true,
552 | "optional": true
553 | },
554 | "esbuild-linux-32": {
555 | "version": "0.14.38",
556 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.38.tgz",
557 | "integrity": "sha512-QfgfeNHRFvr2XeHFzP8kOZVnal3QvST3A0cgq32ZrHjSMFTdgXhMhmWdKzRXP/PKcfv3e2OW9tT9PpcjNvaq6g==",
558 | "dev": true,
559 | "optional": true
560 | },
561 | "esbuild-linux-64": {
562 | "version": "0.14.38",
563 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.38.tgz",
564 | "integrity": "sha512-uuZHNmqcs+Bj1qiW9k/HZU3FtIHmYiuxZ/6Aa+/KHb/pFKr7R3aVqvxlAudYI9Fw3St0VCPfv7QBpUITSmBR1Q==",
565 | "dev": true,
566 | "optional": true
567 | },
568 | "esbuild-linux-arm": {
569 | "version": "0.14.38",
570 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.38.tgz",
571 | "integrity": "sha512-FiFvQe8J3VKTDXG01JbvoVRXQ0x6UZwyrU4IaLBZeq39Bsbatd94Fuc3F1RGqPF5RbIWW7RvkVQjn79ejzysnA==",
572 | "dev": true,
573 | "optional": true
574 | },
575 | "esbuild-linux-arm64": {
576 | "version": "0.14.38",
577 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.38.tgz",
578 | "integrity": "sha512-HlMGZTEsBrXrivr64eZ/EO0NQM8H8DuSENRok9d+Jtvq8hOLzrxfsAT9U94K3KOGk2XgCmkaI2KD8hX7F97lvA==",
579 | "dev": true,
580 | "optional": true
581 | },
582 | "esbuild-linux-mips64le": {
583 | "version": "0.14.38",
584 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.38.tgz",
585 | "integrity": "sha512-qd1dLf2v7QBiI5wwfil9j0HG/5YMFBAmMVmdeokbNAMbcg49p25t6IlJFXAeLzogv1AvgaXRXvgFNhScYEUXGQ==",
586 | "dev": true,
587 | "optional": true
588 | },
589 | "esbuild-linux-ppc64le": {
590 | "version": "0.14.38",
591 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.38.tgz",
592 | "integrity": "sha512-mnbEm7o69gTl60jSuK+nn+pRsRHGtDPfzhrqEUXyCl7CTOCLtWN2bhK8bgsdp6J/2NyS/wHBjs1x8aBWwP2X9Q==",
593 | "dev": true,
594 | "optional": true
595 | },
596 | "esbuild-linux-riscv64": {
597 | "version": "0.14.38",
598 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.38.tgz",
599 | "integrity": "sha512-+p6YKYbuV72uikChRk14FSyNJZ4WfYkffj6Af0/Tw63/6TJX6TnIKE+6D3xtEc7DeDth1fjUOEqm+ApKFXbbVQ==",
600 | "dev": true,
601 | "optional": true
602 | },
603 | "esbuild-linux-s390x": {
604 | "version": "0.14.38",
605 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.38.tgz",
606 | "integrity": "sha512-0zUsiDkGJiMHxBQ7JDU8jbaanUY975CdOW1YDrurjrM0vWHfjv9tLQsW9GSyEb/heSK1L5gaweRjzfUVBFoybQ==",
607 | "dev": true,
608 | "optional": true
609 | },
610 | "esbuild-netbsd-64": {
611 | "version": "0.14.38",
612 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.38.tgz",
613 | "integrity": "sha512-cljBAApVwkpnJZfnRVThpRBGzCi+a+V9Ofb1fVkKhtrPLDYlHLrSYGtmnoTVWDQdU516qYI8+wOgcGZ4XIZh0Q==",
614 | "dev": true,
615 | "optional": true
616 | },
617 | "esbuild-openbsd-64": {
618 | "version": "0.14.38",
619 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.38.tgz",
620 | "integrity": "sha512-CDswYr2PWPGEPpLDUO50mL3WO/07EMjnZDNKpmaxUPsrW+kVM3LoAqr/CE8UbzugpEiflYqJsGPLirThRB18IQ==",
621 | "dev": true,
622 | "optional": true
623 | },
624 | "esbuild-sunos-64": {
625 | "version": "0.14.38",
626 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.38.tgz",
627 | "integrity": "sha512-2mfIoYW58gKcC3bck0j7lD3RZkqYA7MmujFYmSn9l6TiIcAMpuEvqksO+ntBgbLep/eyjpgdplF7b+4T9VJGOA==",
628 | "dev": true,
629 | "optional": true
630 | },
631 | "esbuild-windows-32": {
632 | "version": "0.14.38",
633 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.38.tgz",
634 | "integrity": "sha512-L2BmEeFZATAvU+FJzJiRLFUP+d9RHN+QXpgaOrs2klshoAm1AE6Us4X6fS9k33Uy5SzScn2TpcgecbqJza1Hjw==",
635 | "dev": true,
636 | "optional": true
637 | },
638 | "esbuild-windows-64": {
639 | "version": "0.14.38",
640 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.38.tgz",
641 | "integrity": "sha512-Khy4wVmebnzue8aeSXLC+6clo/hRYeNIm0DyikoEqX+3w3rcvrhzpoix0S+MF9vzh6JFskkIGD7Zx47ODJNyCw==",
642 | "dev": true,
643 | "optional": true
644 | },
645 | "esbuild-windows-arm64": {
646 | "version": "0.14.38",
647 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.38.tgz",
648 | "integrity": "sha512-k3FGCNmHBkqdJXuJszdWciAH77PukEyDsdIryEHn9cKLQFxzhT39dSumeTuggaQcXY57UlmLGIkklWZo2qzHpw==",
649 | "dev": true,
650 | "optional": true
651 | },
652 | "escalade": {
653 | "version": "3.1.1",
654 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
655 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
656 | "dev": true
657 | },
658 | "escape-string-regexp": {
659 | "version": "1.0.5",
660 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
661 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
662 | "dev": true
663 | },
664 | "estree-walker": {
665 | "version": "2.0.2",
666 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
667 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
668 | "dev": true
669 | },
670 | "fsevents": {
671 | "version": "2.3.2",
672 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
673 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
674 | "dev": true,
675 | "optional": true
676 | },
677 | "function-bind": {
678 | "version": "1.1.1",
679 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
680 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
681 | "dev": true
682 | },
683 | "gensync": {
684 | "version": "1.0.0-beta.2",
685 | "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
686 | "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
687 | "dev": true
688 | },
689 | "globals": {
690 | "version": "11.12.0",
691 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
692 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
693 | "dev": true
694 | },
695 | "has": {
696 | "version": "1.0.3",
697 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
698 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
699 | "dev": true,
700 | "requires": {
701 | "function-bind": "^1.1.1"
702 | }
703 | },
704 | "has-flag": {
705 | "version": "3.0.0",
706 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
707 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
708 | "dev": true
709 | },
710 | "hoist-non-react-statics": {
711 | "version": "3.3.2",
712 | "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
713 | "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
714 | "requires": {
715 | "react-is": "^16.7.0"
716 | },
717 | "dependencies": {
718 | "react-is": {
719 | "version": "16.13.1",
720 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
721 | "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
722 | }
723 | }
724 | },
725 | "immer": {
726 | "version": "9.0.12",
727 | "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz",
728 | "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA=="
729 | },
730 | "is-core-module": {
731 | "version": "2.9.0",
732 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz",
733 | "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==",
734 | "dev": true,
735 | "requires": {
736 | "has": "^1.0.3"
737 | }
738 | },
739 | "js-tokens": {
740 | "version": "4.0.0",
741 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
742 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
743 | },
744 | "jsesc": {
745 | "version": "2.5.2",
746 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
747 | "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
748 | "dev": true
749 | },
750 | "json5": {
751 | "version": "2.2.1",
752 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
753 | "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
754 | "dev": true
755 | },
756 | "loose-envify": {
757 | "version": "1.4.0",
758 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
759 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
760 | "requires": {
761 | "js-tokens": "^3.0.0 || ^4.0.0"
762 | }
763 | },
764 | "ms": {
765 | "version": "2.1.2",
766 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
767 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
768 | "dev": true
769 | },
770 | "nanoid": {
771 | "version": "3.3.3",
772 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
773 | "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
774 | "dev": true
775 | },
776 | "node-releases": {
777 | "version": "2.0.3",
778 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz",
779 | "integrity": "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==",
780 | "dev": true
781 | },
782 | "path-parse": {
783 | "version": "1.0.7",
784 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
785 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
786 | "dev": true
787 | },
788 | "picocolors": {
789 | "version": "1.0.0",
790 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
791 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
792 | "dev": true
793 | },
794 | "picomatch": {
795 | "version": "2.3.1",
796 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
797 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
798 | "dev": true
799 | },
800 | "postcss": {
801 | "version": "8.4.12",
802 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz",
803 | "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==",
804 | "dev": true,
805 | "requires": {
806 | "nanoid": "^3.3.1",
807 | "picocolors": "^1.0.0",
808 | "source-map-js": "^1.0.2"
809 | }
810 | },
811 | "react": {
812 | "version": "18.0.0",
813 | "resolved": "https://registry.npmjs.org/react/-/react-18.0.0.tgz",
814 | "integrity": "sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==",
815 | "requires": {
816 | "loose-envify": "^1.1.0"
817 | }
818 | },
819 | "react-dom": {
820 | "version": "18.0.0",
821 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.0.0.tgz",
822 | "integrity": "sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw==",
823 | "requires": {
824 | "loose-envify": "^1.1.0",
825 | "scheduler": "^0.21.0"
826 | }
827 | },
828 | "react-is": {
829 | "version": "18.0.0",
830 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.0.0.tgz",
831 | "integrity": "sha512-yUcBYdBBbo3QiPsgYDcfQcIkGZHfxOaoE6HLSnr1sPzMhdyxusbfKOSUbSd/ocGi32dxcj366PsTj+5oggeKKw=="
832 | },
833 | "react-redux": {
834 | "version": "8.0.1",
835 | "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.1.tgz",
836 | "integrity": "sha512-LMZMsPY4DYdZfLJgd7i79n5Kps5N9XVLCJJeWAaPYTV+Eah2zTuBjTxKtNEbjiyitbq80/eIkm55CYSLqAub3w==",
837 | "requires": {
838 | "@babel/runtime": "^7.12.1",
839 | "@types/hoist-non-react-statics": "^3.3.1",
840 | "@types/use-sync-external-store": "^0.0.3",
841 | "hoist-non-react-statics": "^3.3.2",
842 | "react-is": "^18.0.0",
843 | "use-sync-external-store": "^1.0.0"
844 | }
845 | },
846 | "react-refresh": {
847 | "version": "0.12.0",
848 | "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.12.0.tgz",
849 | "integrity": "sha512-suLIhrU2IHKL5JEKR/fAwJv7bbeq4kJ+pJopf77jHwuR+HmJS/HbrPIGsTBUVfw7tXPOmYv7UJ7PCaN49e8x4A==",
850 | "dev": true
851 | },
852 | "redux": {
853 | "version": "4.2.0",
854 | "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz",
855 | "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==",
856 | "requires": {
857 | "@babel/runtime": "^7.9.2"
858 | }
859 | },
860 | "redux-thunk": {
861 | "version": "2.4.1",
862 | "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
863 | "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q=="
864 | },
865 | "regenerator-runtime": {
866 | "version": "0.13.9",
867 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
868 | "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
869 | },
870 | "reselect": {
871 | "version": "4.1.5",
872 | "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz",
873 | "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ=="
874 | },
875 | "resolve": {
876 | "version": "1.22.0",
877 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
878 | "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
879 | "dev": true,
880 | "requires": {
881 | "is-core-module": "^2.8.1",
882 | "path-parse": "^1.0.7",
883 | "supports-preserve-symlinks-flag": "^1.0.0"
884 | }
885 | },
886 | "rollup": {
887 | "version": "2.70.2",
888 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.70.2.tgz",
889 | "integrity": "sha512-EitogNZnfku65I1DD5Mxe8JYRUCy0hkK5X84IlDtUs+O6JRMpRciXTzyCUuX11b5L5pvjH+OmFXiQ3XjabcXgg==",
890 | "dev": true,
891 | "requires": {
892 | "fsevents": "~2.3.2"
893 | }
894 | },
895 | "safe-buffer": {
896 | "version": "5.1.2",
897 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
898 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
899 | "dev": true
900 | },
901 | "scheduler": {
902 | "version": "0.21.0",
903 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz",
904 | "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==",
905 | "requires": {
906 | "loose-envify": "^1.1.0"
907 | }
908 | },
909 | "semver": {
910 | "version": "6.3.0",
911 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
912 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
913 | "dev": true
914 | },
915 | "source-map": {
916 | "version": "0.5.7",
917 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
918 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
919 | "dev": true
920 | },
921 | "source-map-js": {
922 | "version": "1.0.2",
923 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
924 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
925 | "dev": true
926 | },
927 | "supports-color": {
928 | "version": "5.5.0",
929 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
930 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
931 | "dev": true,
932 | "requires": {
933 | "has-flag": "^3.0.0"
934 | }
935 | },
936 | "supports-preserve-symlinks-flag": {
937 | "version": "1.0.0",
938 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
939 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
940 | "dev": true
941 | },
942 | "to-fast-properties": {
943 | "version": "2.0.0",
944 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
945 | "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
946 | "dev": true
947 | },
948 | "typescript": {
949 | "version": "4.6.3",
950 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz",
951 | "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==",
952 | "dev": true
953 | },
954 | "use-sync-external-store": {
955 | "version": "1.0.0",
956 | "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.0.0.tgz",
957 | "integrity": "sha512-AFVsxg5GkFg8GDcxnl+Z0lMAz9rE8DGJCc28qnBuQF7lac57B5smLcT37aXpXIIPz75rW4g3eXHPjhHwdGskOw=="
958 | },
959 | "vite": {
960 | "version": "2.9.5",
961 | "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.5.tgz",
962 | "integrity": "sha512-dvMN64X2YEQgSXF1lYabKXw3BbN6e+BL67+P3Vy4MacnY+UzT1AfkHiioFSi9+uiDUiaDy7Ax/LQqivk6orilg==",
963 | "dev": true,
964 | "requires": {
965 | "esbuild": "^0.14.27",
966 | "fsevents": "~2.3.2",
967 | "postcss": "^8.4.12",
968 | "resolve": "^1.22.0",
969 | "rollup": "^2.59.0"
970 | }
971 | }
972 | }
973 | }
974 |
--------------------------------------------------------------------------------
/typescript/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-react-template-redux",
3 | "private": true,
4 | "version": "0.0.0",
5 | "scripts": {
6 | "dev": "vite",
7 | "build": "tsc && vite build",
8 | "preview": "vite preview"
9 | },
10 | "dependencies": {
11 | "@reduxjs/toolkit": "^1.8.1",
12 | "react": "^18.0.0",
13 | "react-dom": "^18.0.0",
14 | "react-redux": "^8.0.1"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.0.0",
18 | "@types/react-dom": "^18.0.0",
19 | "@vitejs/plugin-react": "^1.3.0",
20 | "typescript": "^4.6.3",
21 | "vite": "^2.9.5"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/typescript/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-float infinite 3s ease-in-out;
13 | }
14 | }
15 |
16 | .App-header {
17 | min-height: 100vh;
18 | display: flex;
19 | flex-direction: column;
20 | align-items: center;
21 | justify-content: center;
22 | font-size: calc(10px + 2vmin);
23 | }
24 |
25 | .App-link {
26 | color: rgb(112, 76, 182);
27 | }
28 |
29 | @keyframes App-logo-float {
30 | 0% {
31 | transform: translateY(0);
32 | }
33 | 50% {
34 | transform: translateY(10px);
35 | }
36 | 100% {
37 | transform: translateY(0px);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/typescript/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import logo from "./logo.svg";
3 | import { Counter } from "./features/counter/Counter";
4 | import "./App.css";
5 |
6 | function App() {
7 | return (
8 |
55 | );
56 | }
57 |
58 | export default App;
59 |
--------------------------------------------------------------------------------
/typescript/src/app/hooks.ts:
--------------------------------------------------------------------------------
1 | import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
2 | import type { RootState, AppDispatch } from "./store";
3 |
4 | // Use throughout your app instead of plain `useDispatch` and `useSelector`
5 | export const useAppDispatch = () => useDispatch();
6 | export const useAppSelector: TypedUseSelectorHook = useSelector;
7 |
--------------------------------------------------------------------------------
/typescript/src/app/store.ts:
--------------------------------------------------------------------------------
1 | import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";
2 | import counterReducer from "../features/counter/counterSlice";
3 |
4 | export const store = configureStore({
5 | reducer: {
6 | counter: counterReducer,
7 | },
8 | });
9 |
10 | export type AppDispatch = typeof store.dispatch;
11 | export type RootState = ReturnType;
12 | export type AppThunk = ThunkAction<
13 | ReturnType,
14 | RootState,
15 | unknown,
16 | Action
17 | >;
18 |
--------------------------------------------------------------------------------
/typescript/src/features/counter/Counter.module.css:
--------------------------------------------------------------------------------
1 | .row {
2 | display: flex;
3 | align-items: center;
4 | justify-content: center;
5 | }
6 |
7 | .row > button {
8 | margin-left: 4px;
9 | margin-right: 8px;
10 | }
11 |
12 | .row:not(:last-child) {
13 | margin-bottom: 16px;
14 | }
15 |
16 | .value {
17 | font-size: 78px;
18 | padding-left: 16px;
19 | padding-right: 16px;
20 | margin-top: 2px;
21 | font-family: "Courier New", Courier, monospace;
22 | }
23 |
24 | .button {
25 | appearance: none;
26 | background: none;
27 | font-size: 32px;
28 | padding-left: 12px;
29 | padding-right: 12px;
30 | outline: none;
31 | border: 2px solid transparent;
32 | color: rgb(112, 76, 182);
33 | padding-bottom: 4px;
34 | cursor: pointer;
35 | background-color: rgba(112, 76, 182, 0.1);
36 | border-radius: 2px;
37 | transition: all 0.15s;
38 | }
39 |
40 | .textbox {
41 | font-size: 32px;
42 | padding: 2px;
43 | width: 64px;
44 | text-align: center;
45 | margin-right: 4px;
46 | }
47 |
48 | .button:hover,
49 | .button:focus {
50 | border: 2px solid rgba(112, 76, 182, 0.4);
51 | }
52 |
53 | .button:active {
54 | background-color: rgba(112, 76, 182, 0.2);
55 | }
56 |
57 | .asyncButton {
58 | composes: button;
59 | position: relative;
60 | }
61 |
62 | .asyncButton:after {
63 | content: "";
64 | background-color: rgba(112, 76, 182, 0.15);
65 | display: block;
66 | position: absolute;
67 | width: 100%;
68 | height: 100%;
69 | left: 0;
70 | top: 0;
71 | opacity: 0;
72 | transition: width 1s linear, opacity 0.5s ease 1s;
73 | }
74 |
75 | .asyncButton:active:after {
76 | width: 0%;
77 | opacity: 1;
78 | transition: 0s;
79 | }
80 |
--------------------------------------------------------------------------------
/typescript/src/features/counter/Counter.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 |
3 | import { useAppSelector, useAppDispatch } from "../../app/hooks";
4 | import {
5 | decrement,
6 | increment,
7 | incrementByAmount,
8 | incrementAsync,
9 | incrementIfOdd,
10 | selectCount,
11 | } from "./counterSlice";
12 | import styles from "./Counter.module.css";
13 |
14 | export function Counter() {
15 | const count = useAppSelector(selectCount);
16 | const dispatch = useAppDispatch();
17 | const [incrementAmount, setIncrementAmount] = useState("2");
18 |
19 | const incrementValue = Number(incrementAmount) || 0;
20 |
21 | return (
22 |
23 |
24 |
31 | {count}
32 |
39 |
40 |
41 | setIncrementAmount(e.target.value)}
46 | />
47 |
53 |
59 |
65 |
66 |
67 | );
68 | }
69 |
--------------------------------------------------------------------------------
/typescript/src/features/counter/counterAPI.ts:
--------------------------------------------------------------------------------
1 | // A mock function to mimic making an async request for data
2 | export function fetchCount(amount = 1) {
3 | return new Promise<{ data: number }>((resolve) =>
4 | setTimeout(() => resolve({ data: amount }), 500)
5 | );
6 | }
7 |
--------------------------------------------------------------------------------
/typescript/src/features/counter/counterSlice.ts:
--------------------------------------------------------------------------------
1 | import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit";
2 | import { RootState, AppThunk } from "../../app/store";
3 | import { fetchCount } from "./counterAPI";
4 |
5 | export interface CounterState {
6 | value: number;
7 | status: "idle" | "loading" | "failed";
8 | }
9 |
10 | const initialState: CounterState = {
11 | value: 0,
12 | status: "idle",
13 | };
14 |
15 | // The function below is called a thunk and allows us to perform async logic. It
16 | // can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
17 | // will call the thunk with the `dispatch` function as the first argument. Async
18 | // code can then be executed and other actions can be dispatched. Thunks are
19 | // typically used to make async requests.
20 | export const incrementAsync = createAsyncThunk(
21 | "counter/fetchCount",
22 | async (amount: number) => {
23 | const response = await fetchCount(amount);
24 | // The value we return becomes the `fulfilled` action payload
25 | return response.data;
26 | }
27 | );
28 |
29 | export const counterSlice = createSlice({
30 | name: "counter",
31 | initialState,
32 | // The `reducers` field lets us define reducers and generate associated actions
33 | reducers: {
34 | increment: (state) => {
35 | // Redux Toolkit allows us to write "mutating" logic in reducers. It
36 | // doesn't actually mutate the state because it uses the Immer library,
37 | // which detects changes to a "draft state" and produces a brand new
38 | // immutable state based off those changes
39 | state.value += 1;
40 | },
41 | decrement: (state) => {
42 | state.value -= 1;
43 | },
44 | // Use the PayloadAction type to declare the contents of `action.payload`
45 | incrementByAmount: (state, action: PayloadAction) => {
46 | state.value += action.payload;
47 | },
48 | },
49 | // The `extraReducers` field lets the slice handle actions defined elsewhere,
50 | // including actions generated by createAsyncThunk or in other slices.
51 | extraReducers: (builder) => {
52 | builder
53 | .addCase(incrementAsync.pending, (state) => {
54 | state.status = "loading";
55 | })
56 | .addCase(incrementAsync.fulfilled, (state, action) => {
57 | state.status = "idle";
58 | state.value += action.payload;
59 | })
60 | .addCase(incrementAsync.rejected, (state) => {
61 | state.status = "failed";
62 | });
63 | },
64 | });
65 |
66 | export const { increment, decrement, incrementByAmount } = counterSlice.actions;
67 |
68 | // The function below is called a selector and allows us to select a value from
69 | // the state. Selectors can also be defined inline where they're used instead of
70 | // in the slice file. For example: `useSelector((state: RootState) => state.counter.value)`
71 | export const selectCount = (state: RootState) => state.counter.value;
72 |
73 | // We can also write thunks by hand, which may contain both sync and async logic.
74 | // Here's an example of conditionally dispatching actions based on current state.
75 | export const incrementIfOdd =
76 | (amount: number): AppThunk =>
77 | (dispatch, getState) => {
78 | const currentValue = selectCount(getState());
79 | if (currentValue % 2 === 1) {
80 | dispatch(incrementByAmount(amount));
81 | }
82 | };
83 |
84 | export default counterSlice.reducer;
85 |
--------------------------------------------------------------------------------
/typescript/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/typescript/src/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/typescript/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import { Provider } from "react-redux";
4 | import { store } from "./app/store";
5 | import App from "./App";
6 | import "./index.css";
7 |
8 | ReactDOM.createRoot(document.getElementById("root")!).render(
9 |
10 |
11 |
12 |
13 |
14 | );
15 |
--------------------------------------------------------------------------------
/typescript/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/typescript/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx"
18 | },
19 | "include": ["src"],
20 | "references": [{ "path": "./tsconfig.node.json" }]
21 | }
22 |
--------------------------------------------------------------------------------
/typescript/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "esnext",
5 | "moduleResolution": "node"
6 | },
7 | "include": ["vite.config.ts"]
8 | }
9 |
--------------------------------------------------------------------------------
/typescript/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 |
--------------------------------------------------------------------------------