@fun-tools/store 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,174 +1,228 @@
1
1
  # @fun-tools/store
2
2
 
3
- > A lightweight, type-safe external store library for React, React Native, and Next.js
3
+ > A simple and lightweight state management library for React apps
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@fun-tools/store.svg)](https://www.npmjs.com/package/@fun-tools/store)
6
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
6
 
8
- ## 📋 Overview
7
+ ## 📋 What is @fun-tools/store?
9
8
 
10
- `@fun-tools/store` is a minimal yet powerful state management solution built on React's `useSyncExternalStore` API. It provides automatic handler generation, TypeScript support, and works seamlessly across React, React Native, and Next.js applications.
9
+ `@fun-tools/store` is an easy-to-use state management library for React. Think of it as a smarter way to share data between your components without the complexity of Redux or other heavy tools.
11
10
 
12
- ## Features
11
+ **Perfect for beginners and experienced developers alike!**
13
12
 
14
- - **🎯 Type-Safe**: Full TypeScript support with intelligent type inference
15
- - **⚡ Lightweight**: Minimal bundle size with zero dependencies (except React peer dependency)
16
- - **🔄 Auto-Generated Handlers**: Automatic CRUD operations for arrays, objects, and primitives
17
- - **🪝 Custom Handlers**: Define your own sync and async state handlers
18
- - **🎨 Flexible API**: Use as a global store or scoped with React Context
19
- - **📦 Tree-Shakeable**: Only bundle what you use
20
- - **🚀 Performance Optimized**: Built-in shallow equality checks and snapshot caching
13
+ ## Why Choose @fun-tools/store?
14
+
15
+ - **Super Easy to Learn** - Get started in minutes, not hours
16
+ - **Automatic Features** - Get built-in functions for free (no need to write repetitive code)
17
+ - **TypeScript Friendly** - Get helpful suggestions as you type
18
+ - **Very Small** - Won't bloat your app size
19
+ - **Fast Performance** - Components only update when they need to
20
+ - ✅ **Works Everywhere** - React, React Native, and Next.js
21
21
 
22
22
  ## 📦 Installation
23
23
 
24
- ```bash
25
- npm install @fun-tools/store
26
- ```
24
+ Choose your favorite package manager:
27
25
 
28
26
  ```bash
29
- yarn add @fun-tools/store
27
+ npm install @fun-tools/store
30
28
  ```
31
29
 
32
- ```bash
33
- pnpm add @fun-tools/store
34
- ```
30
+ ## 🚀 Quick Start - Your First Store
35
31
 
36
- ## 🚀 Quick Start
32
+ Let's create a simple counter in 3 easy steps:
37
33
 
38
- ### Basic Usage (Global Store)
34
+ ### Step 1: Create Your Store
39
35
 
40
36
  ```tsx
41
- import { createStore } from "@ex/store";
37
+ import { createStore } from "@fun-tools/store";
42
38
 
43
- // Define your store
44
- const store = createStore({
39
+ // Create a store with initial values
40
+ const counterStore = createStore({
45
41
  states: {
46
- count: 0,
47
- user: { name: "John", age: 25 },
48
- items: ["apple", "banana"],
42
+ count: 0, // Our counter starts at 0
49
43
  },
50
44
  });
45
+ ```
46
+
47
+ ### Step 2: Use It in a Component
51
48
 
52
- // Use in components
49
+ ```tsx
53
50
  function Counter() {
54
- const { count } = store.useStore((state) => ({ count: state.count }));
55
- const handlers = store.useHandlers();
51
+ // Get the count value
52
+ const count = counterStore.useStore((state) => state.count);
53
+
54
+ // Get the handlers (functions to change the state)
55
+ const handlers = counterStore.useHandlers();
56
56
 
57
57
  return (
58
58
  <div>
59
- <p>Count: {count}</p>
59
+ <h1>Count: {count}</h1>
60
+ {/* Set count to a specific number */}
61
+ <button onClick={() => handlers.count.set(10)}>Set to 10</button>
62
+ {/* Increment using current value */}
60
63
  <button onClick={() => handlers.count.set((prev) => prev + 1)}>
61
- Increment
64
+ Add 1
62
65
  </button>
66
+ {/* Reset to initial value (0) */}
63
67
  <button onClick={() => handlers.count.reset()}>Reset</button>
64
68
  </div>
65
69
  );
66
70
  }
67
71
  ```
68
72
 
69
- ### Context-Based Store (Scoped)
73
+ That's it! You have a working counter. 🎉
70
74
 
71
- ```tsx
72
- import { createStoreProvider } from "@ex/store";
75
+ ## 📖 Core Concepts
73
76
 
74
- // Create provider
75
- const { Provider, useStore, useHandlers } = createStoreProvider({
77
+ ### 1. Creating a Store
78
+
79
+ A store is where you keep your app's data. It's like a box that holds all your values.
80
+
81
+ ```tsx
82
+ const myStore = createStore({
76
83
  states: {
77
- theme: "light",
78
- settings: { notifications: true },
84
+ // Put all your data here
85
+ userName: "John",
86
+ age: 25,
87
+ isLoggedIn: false,
79
88
  },
80
89
  });
90
+ ```
81
91
 
82
- // Wrap your app
83
- function App() {
84
- return (
85
- <Provider>
86
- <ThemeToggle />
87
- </Provider>
88
- );
89
- }
92
+ ### 2. Reading Data from the Store
90
93
 
91
- // Use in child components
92
- function ThemeToggle() {
93
- const { theme } = useStore((state) => ({ theme: state.theme }));
94
- const handlers = useHandlers();
94
+ Use `useStore` to read data in your components:
95
+
96
+ ```tsx
97
+ function MyComponent() {
98
+ // Method 1: Get one value
99
+ const userName = myStore.useStore((state) => state.userName);
100
+
101
+ // Method 2: Get multiple values
102
+ const { userName, age } = myStore.useStore((state) => ({
103
+ userName: state.userName,
104
+ age: state.age,
105
+ }));
95
106
 
96
107
  return (
97
- <button
98
- onClick={() => handlers.theme.set(theme === "light" ? "dark" : "light")}
99
- >
100
- Current: {theme}
101
- </button>
108
+ <div>
109
+ Hello, {userName}! You are {age} years old.
110
+ </div>
102
111
  );
103
112
  }
104
113
  ```
105
114
 
106
- ## 📖 API Reference
115
+ ### 3. Changing Data (Using Handlers)
107
116
 
108
- ### `createStore(config)`
117
+ Handlers are functions that change your data. The library creates them automatically!
109
118
 
110
- Creates a global store instance.
119
+ ```tsx
120
+ function MyComponent() {
121
+ const handlers = myStore.useHandlers();
122
+
123
+ // Change the userName
124
+ handlers.userName.set("Jane");
111
125
 
112
- **Parameters:**
126
+ // Reset to initial value
127
+ handlers.userName.reset();
128
+ }
129
+ ```
113
130
 
114
- - `states`: Initial state object
115
- - `syncHandlers?`: Custom synchronous handlers (optional)
116
- - `asyncHandlers?`: Custom asynchronous handlers (optional)
131
+ ## 🎨 Auto-Generated Handlers
117
132
 
118
- **Returns:**
133
+ The best part? You get **FREE handlers** based on your data type!
119
134
 
120
- - `useStore<T>(selector)`: Hook to select and subscribe to state
121
- - `useHandlers()`: Hook to access all handlers
135
+ ### For Simple Values (String, Number)
122
136
 
123
- ### `createStoreProvider(config)`
137
+ ```tsx
138
+ const store = createStore({
139
+ states: {
140
+ name: "John",
141
+ age: 25,
142
+ },
143
+ });
124
144
 
125
- Creates a context-based store provider.
145
+ const handlers = store.useHandlers();
126
146
 
127
- **Parameters:**
147
+ // ✅ Set to a new value
148
+ handlers.name.set("Jane");
149
+ handlers.age.set(26);
128
150
 
129
- - Same as `createStore`
151
+ // Set using current value
152
+ handlers.age.set((currentAge) => currentAge + 1);
130
153
 
131
- **Returns:**
154
+ // ✅ Reset to initial value
155
+ handlers.name.reset(); // Back to "John"
156
+ handlers.age.reset(); // Back to 25
157
+ ```
132
158
 
133
- - `Provider`: React component to wrap your app
134
- - `useStore<T>(selector)`: Hook to select and subscribe to state
135
- - `useHandlers()`: Hook to access all handlers
159
+ ### For Boolean (True/False)
136
160
 
137
- ## 🎨 Auto-Generated Handlers
161
+ ```tsx
162
+ const store = createStore({
163
+ states: {
164
+ isOpen: false,
165
+ isDarkMode: true,
166
+ },
167
+ });
138
168
 
139
- The library automatically generates handlers based on your state types:
169
+ const handlers = store.useHandlers();
140
170
 
141
- ### For All Types
171
+ // Toggle (switch between true/false)
172
+ handlers.isOpen.toggle();
142
173
 
143
- ```tsx
144
- // Set value (supports callbacks)
145
- handlers.count.set(10);
146
- handlers.count.set((prev) => prev + 1);
174
+ // ✅ Set to specific value
175
+ handlers.isDarkMode.set(false);
147
176
 
148
- // Reset to initial value
149
- handlers.count.reset();
177
+ // Reset to initial value
178
+ handlers.isOpen.reset();
150
179
  ```
151
180
 
152
- ### For Arrays
181
+ ### For Arrays (Lists)
153
182
 
154
183
  ```tsx
155
184
  const store = createStore({
156
- states: { items: ["a", "b", "c"] },
185
+ states: {
186
+ fruits: ["apple", "banana"],
187
+ numbers: [1, 2, 3],
188
+ },
157
189
  });
158
190
 
159
191
  const handlers = store.useHandlers();
160
192
 
161
- // Add items
162
- handlers.items.push("d");
163
- handlers.items.unshift("z");
193
+ // Add to end
194
+ handlers.fruits.push("orange");
195
+ // Result: ["apple", "banana", "orange"]
196
+
197
+ // ✅ Add to beginning
198
+ handlers.fruits.unShift("mango");
199
+ // Result: ["mango", "apple", "banana", "orange"]
164
200
 
165
- // Remove items
166
- handlers.items.pop();
167
- handlers.items.shift();
201
+ // Remove from end
202
+ handlers.fruits.pop();
203
+ // Result: ["mango", "apple", "banana"]
168
204
 
169
- // Transform
170
- handlers.items.filter((item) => item !== "b");
171
- handlers.items.map((item) => item.toUpperCase());
205
+ // ✅ Remove from beginning
206
+ handlers.fruits.shift();
207
+ // Result: ["apple", "banana"]
208
+
209
+ // ✅ Update item at specific position
210
+ handlers.fruits.update(0, "grape");
211
+ // Result: ["grape", "banana"]
212
+
213
+ // ✅ Update item using current value
214
+ handlers.numbers.update(1, (current) => current * 2);
215
+
216
+ // ✅ Remove item at specific position
217
+ handlers.fruits.remove(1);
218
+ // Result: ["grape"]
219
+
220
+ // ✅ Set entire array
221
+ handlers.fruits.set(["kiwi", "melon"]);
222
+
223
+ // ✅ Reset to initial value
224
+ handlers.fruits.reset();
225
+ // Result: ["apple", "banana"]
172
226
  ```
173
227
 
174
228
  ### For Objects
@@ -178,210 +232,284 @@ const store = createStore({
178
232
  states: {
179
233
  user: {
180
234
  name: "John",
181
- address: { city: "NYC", zip: "10001" },
235
+ email: "john@example.com",
236
+ settings: {
237
+ theme: "light",
238
+ notifications: true,
239
+ },
182
240
  },
183
241
  },
184
242
  });
185
243
 
186
244
  const handlers = store.useHandlers();
187
245
 
188
- // Update single nested property
246
+ // Update single property
189
247
  handlers.user.update("name", "Jane");
190
- handlers.user.update("address.city", "LA");
191
248
 
192
- // Update multiple properties (deep merge)
249
+ // Update with current value
250
+ handlers.user.update("name", (currentName) => currentName.toUpperCase());
251
+
252
+ // ✅ Update nested property (use dot notation)
253
+ handlers.user.update("settings.theme", "dark");
254
+
255
+ // ✅ Update multiple properties at once
193
256
  handlers.user.updateMany({
194
257
  name: "Jane",
195
- address: { city: "LA" },
258
+ email: "jane@example.com",
196
259
  });
260
+
261
+ // ✅ Update nested properties
262
+ handlers.user.updateMany({
263
+ settings: {
264
+ theme: "dark",
265
+ },
266
+ });
267
+
268
+ // ✅ Set entire object
269
+ handlers.user.set({
270
+ name: "Bob",
271
+ email: "bob@example.com",
272
+ settings: { theme: "blue", notifications: false },
273
+ });
274
+
275
+ // ✅ Reset to initial value
276
+ handlers.user.reset();
197
277
  ```
198
278
 
199
279
  ## 🔧 Custom Handlers
200
280
 
201
- ### Sync Handlers
281
+ Sometimes you need custom logic. Create your own handlers!
282
+
283
+ ### Sync Handlers (Instant Changes)
202
284
 
203
285
  ```tsx
204
286
  const store = createStore({
205
287
  states: {
206
288
  count: 0,
289
+ firstName: "John",
290
+ lastName: "Doe",
207
291
  },
292
+
293
+ // Define your custom handlers here
208
294
  syncHandlers: {
209
- increment: (states) => {
210
- states.count++;
295
+ // Handler with no parameters
296
+ increment: (state) => {
297
+ state.count = state.count + 1;
298
+ },
299
+
300
+ // Handler with parameters
301
+ incrementBy: (state, amount: number) => {
302
+ state.count = state.count + amount;
211
303
  },
212
- incrementBy: (states, amount: number) => {
213
- states.count += amount;
304
+
305
+ // Handler that changes multiple values
306
+ setFullName: (state, first: string, last: string) => {
307
+ state.firstName = first;
308
+ state.lastName = last;
214
309
  },
215
310
  },
216
311
  });
217
312
 
218
- // Usage
219
- const handlers = store.useHandlers();
220
- handlers.increment(); // count + 1
221
- handlers.incrementBy(5); // count + 5
313
+ // Use them in components
314
+ function MyComponent() {
315
+ const handlers = store.useHandlers();
316
+
317
+ return (
318
+ <div>
319
+ <button onClick={() => handlers.increment()}>Add 1</button>
320
+ <button onClick={() => handlers.incrementBy(5)}>Add 5</button>
321
+ <button onClick={() => handlers.setFullName("Jane", "Smith")}>
322
+ Change Name
323
+ </button>
324
+ </div>
325
+ );
326
+ }
222
327
  ```
223
328
 
224
- ### Async Handlers
329
+ ### Async Handlers (For API Calls)
330
+
331
+ Perfect for fetching data from servers!
225
332
 
226
333
  ```tsx
227
334
  const store = createStore({
228
335
  states: {
229
336
  user: null,
230
337
  loading: false,
338
+ error: null,
231
339
  },
340
+
232
341
  asyncHandlers: {
233
- fetchUser: async (states, userId: string) => {
234
- states.loading = true;
235
- const response = await fetch(`/api/users/${userId}`);
236
- states.user = await response.json();
237
- states.loading = false;
342
+ // Fetch user from API
343
+ fetchUser: async (state, userId: string) => {
344
+ // Set loading to true
345
+ state.loading = true;
346
+ state.error = null;
347
+
348
+ try {
349
+ // Fetch from API
350
+ const response = await fetch(`https://api.example.com/users/${userId}`);
351
+ const data = await response.json();
352
+
353
+ // Update state with data
354
+ state.user = data;
355
+ } catch (err) {
356
+ // Handle errors
357
+ state.error = "Failed to fetch user";
358
+ } finally {
359
+ // Set loading to false
360
+ state.loading = false;
361
+ }
238
362
  },
239
363
  },
240
364
  });
241
365
 
242
- // Usage
243
- const handlers = store.useHandlers();
244
- await handlers.fetchUser("123");
245
- ```
246
-
247
- ## 💡 Advanced Usage
248
-
249
- ### Selective Subscriptions
250
-
251
- The `useStore` selector ensures components only re-render when selected state changes:
252
-
253
- ```tsx
254
- // Component only re-renders when 'count' changes
255
- function CountDisplay() {
256
- const { count } = store.useStore((state) => ({ count: state.count }));
257
- return <div>{count}</div>;
258
- }
259
-
260
- // Component only re-renders when 'user.name' changes
261
- function UserName() {
262
- const { name } = store.useStore((state) => ({
263
- name: state.user.name,
366
+ // Use in component
367
+ function UserProfile() {
368
+ const { user, loading } = store.useStore((state) => ({
369
+ user: state.user,
370
+ loading: state.loading,
264
371
  }));
265
- return <div>{name}</div>;
372
+ const handlers = store.useHandlers();
373
+
374
+ return (
375
+ <div>
376
+ <button onClick={() => handlers.fetchUser("123")}>Load User</button>
377
+ {loading && <p>Loading...</p>}
378
+ {user && <p>Name: {user.name}</p>}
379
+ </div>
380
+ );
266
381
  }
267
382
  ```
268
383
 
269
- ### Multiple Stores
384
+ ## 🎁 Using Providers (Scoped Stores)
270
385
 
271
- You can create multiple independent stores:
386
+ Sometimes you want a store that only works within a specific part of your app. Use `createStoreProvider`!
272
387
 
273
388
  ```tsx
274
- const authStore = createStore({
275
- states: { user: null, isAuthenticated: false },
276
- });
389
+ import { createStoreProvider } from "@fun-tools/store";
277
390
 
278
- const cartStore = createStore({
279
- states: { items: [], total: 0 },
391
+ // Create a provider
392
+ const { Provider, useStore, useHandlers } = createStoreProvider({
393
+ states: {
394
+ theme: "light",
395
+ language: "en",
396
+ },
280
397
  });
281
398
 
399
+ // Wrap part of your app
282
400
  function App() {
283
- const { user } = authStore.useStore((state) => ({ user: state.user }));
284
- const { items } = cartStore.useStore((state) => ({ items: state.items }));
285
-
286
- // ...
401
+ return (
402
+ <Provider>
403
+ <Header />
404
+ <Content />
405
+ </Provider>
406
+ );
287
407
  }
288
- ```
289
-
290
- ### TypeScript Type Inference
291
-
292
- The library provides full type safety with intelligent inference:
293
408
 
294
- ```tsx
295
- const store = createStore({
296
- states: {
297
- count: 0,
298
- user: { name: "John", age: 25 },
299
- },
300
- syncHandlers: {
301
- setUserAge: (states, age: number) => {
302
- states.user.age = age;
303
- },
304
- },
305
- });
409
+ // Use in any child component
410
+ function Header() {
411
+ const theme = useStore((state) => state.theme);
412
+ const handlers = useHandlers();
306
413
 
307
- const handlers = store.useHandlers();
414
+ return (
415
+ <button
416
+ onClick={() => handlers.theme.set(theme === "light" ? "dark" : "light")}
417
+ >
418
+ Current theme: {theme}
419
+ </button>
420
+ );
421
+ }
422
+ ```
308
423
 
309
- // ✅ TypeScript knows the types
310
- handlers.count.set(10); // ✓
311
- handlers.user.update("name", "Jane"); // ✓
312
- handlers.setUserAge(30); // ✓
424
+ **The difference:**
313
425
 
314
- // TypeScript catches errors
315
- handlers.count.set("invalid"); // Error: Argument of type 'string' is not assignable
316
- handlers.setUserAge("invalid"); // Error: Argument of type 'string' is not assignable
317
- ```
426
+ - `createStore` = Global (available everywhere)
427
+ - `createStoreProvider` = Scoped (only available inside `<Provider>`)
318
428
 
319
- ## 🏗️ Architecture
429
+ ## 💡 Performance Tips
320
430
 
321
- The library uses React's `useSyncExternalStore` API for optimal performance and compatibility:
431
+ ### Only Re-render When Needed
322
432
 
323
- - **Snapshot Caching**: Prevents unnecessary re-renders with shallow equality checks
324
- - **WeakMap Storage**: Efficient snapshot management with automatic garbage collection
325
- - **Immutable Updates**: State changes create new references for proper React updates
326
- - **Subscription Management**: Automatic cleanup when components unmount
433
+ Components only re-render when the data they use changes:
327
434
 
328
- ## 🎯 Use Cases
435
+ ```tsx
436
+ // ❌ BAD: Component re-renders on ANY state change
437
+ const allState = store.useStore((state) => state);
329
438
 
330
- Perfect for:
439
+ // ✅ GOOD: Component only re-renders when count changes
440
+ const count = store.useStore((state) => state.count);
331
441
 
332
- -Small to medium-sized applications
333
- - Quick prototyping and MVPs
334
- - ✅ React Native mobile apps
335
- - ✅ Next.js applications (SSR compatible)
336
- - ✅ Projects needing simple global state
337
- - ✅ Teams wanting minimal state management setup
442
+ //GOOD: Component only re-renders when name or age change
443
+ const { name, age } = store.useStore((state) => ({
444
+ name: state.name,
445
+ age: state.age,
446
+ }));
447
+ ```
338
448
 
339
- ## 📝 Examples
449
+ ## 📚 Real-World Examples
340
450
 
341
- ### Todo App
451
+ ### Example 1: Todo App
342
452
 
343
453
  ```tsx
344
454
  const todoStore = createStore({
345
455
  states: {
346
- todos: [] as Array<{ id: string; text: string; completed: boolean }>,
456
+ todos: [] as Array<{ id: number; text: string; done: boolean }>,
347
457
  },
458
+
348
459
  syncHandlers: {
349
- addTodo: (states, text: string) => {
350
- states.todos.push({
351
- id: Date.now().toString(),
352
- text,
353
- completed: false,
460
+ addTodo: (state, text: string) => {
461
+ state.todos.push({
462
+ id: Date.now(),
463
+ text: text,
464
+ done: false,
354
465
  });
355
466
  },
356
- toggleTodo: (states, id: string) => {
357
- const todo = states.todos.find((t) => t.id === id);
358
- if (todo) todo.completed = !todo.completed;
467
+
468
+ toggleTodo: (state, id: number) => {
469
+ const todo = state.todos.find((t) => t.id === id);
470
+ if (todo) {
471
+ todo.done = !todo.done;
472
+ }
359
473
  },
360
- removeTodo: (states, id: string) => {
361
- states.todos = states.todos.filter((t) => t.id !== id);
474
+
475
+ deleteTodo: (state, id: number) => {
476
+ state.todos = state.todos.filter((t) => t.id !== id);
362
477
  },
363
478
  },
364
479
  });
365
480
 
366
- function TodoList() {
367
- const { todos } = todoStore.useStore((state) => ({ todos: state.todos }));
481
+ function TodoApp() {
482
+ const todos = todoStore.useStore((state) => state.todos);
368
483
  const handlers = todoStore.useHandlers();
484
+ const [input, setInput] = React.useState("");
369
485
 
370
486
  return (
371
487
  <div>
488
+ <input
489
+ value={input}
490
+ onChange={(e) => setInput(e.target.value)}
491
+ placeholder="Add a todo..."
492
+ />
493
+ <button
494
+ onClick={() => {
495
+ handlers.addTodo(input);
496
+ setInput("");
497
+ }}
498
+ >
499
+ Add
500
+ </button>
501
+
372
502
  {todos.map((todo) => (
373
503
  <div key={todo.id}>
374
504
  <input
375
505
  type="checkbox"
376
- checked={todo.completed}
506
+ checked={todo.done}
377
507
  onChange={() => handlers.toggleTodo(todo.id)}
378
508
  />
379
- <span
380
- style={{ textDecoration: todo.completed ? "line-through" : "none" }}
381
- >
509
+ <span style={{ textDecoration: todo.done ? "line-through" : "none" }}>
382
510
  {todo.text}
383
511
  </span>
384
- <button onClick={() => handlers.removeTodo(todo.id)}>Delete</button>
512
+ <button onClick={() => handlers.deleteTodo(todo.id)}>Delete</button>
385
513
  </div>
386
514
  ))}
387
515
  </div>
@@ -389,49 +517,208 @@ function TodoList() {
389
517
  }
390
518
  ```
391
519
 
392
- ### Form Management
520
+ ### Example 2: Shopping Cart
393
521
 
394
522
  ```tsx
395
- const formStore = createStore({
523
+ const cartStore = createStore({
396
524
  states: {
397
- formData: {
398
- username: "",
399
- email: "",
400
- bio: "",
401
- },
402
- errors: {} as Record<string, string>,
525
+ items: [] as Array<{
526
+ id: number;
527
+ name: string;
528
+ price: number;
529
+ quantity: number;
530
+ }>,
531
+ total: 0,
403
532
  },
533
+
404
534
  syncHandlers: {
405
- updateField: (
406
- states,
407
- { field, value }: { field: string; value: string }
408
- ) => {
409
- states.formData = { ...states.formData, [field]: value };
535
+ addItem: (state, product: { id: number; name: string; price: number }) => {
536
+ // Check if item already exists
537
+ const existing = state.items.find((item) => item.id === product.id);
538
+
539
+ if (existing) {
540
+ // Increase quantity
541
+ existing.quantity++;
542
+ } else {
543
+ // Add new item
544
+ state.items.push({ ...product, quantity: 1 });
545
+ }
546
+
547
+ // Update total
548
+ state.total = state.items.reduce(
549
+ (sum, item) => sum + item.price * item.quantity,
550
+ 0
551
+ );
410
552
  },
411
- validate: (states) => {
412
- const errors: Record<string, string> = {};
413
- if (!states.formData.username) errors.username = "Required";
414
- if (!states.formData.email.includes("@")) errors.email = "Invalid email";
415
- states.errors = errors;
553
+
554
+ removeItem: (state, id: number) => {
555
+ state.items = state.items.filter((item) => item.id !== id);
556
+ state.total = state.items.reduce(
557
+ (sum, item) => sum + item.price * item.quantity,
558
+ 0
559
+ );
560
+ },
561
+
562
+ clearCart: (state) => {
563
+ state.items = [];
564
+ state.total = 0;
416
565
  },
417
566
  },
418
567
  });
419
568
  ```
420
569
 
421
- ## 🤝 Contributing
570
+ ### Example 3: User Authentication
422
571
 
423
- Contributions are welcome! Please feel free to submit a Pull Request.
572
+ ```tsx
573
+ const authStore = createStore({
574
+ states: {
575
+ user: null as { id: string; name: string; email: string } | null,
576
+ isAuthenticated: false,
577
+ isLoading: false,
578
+ },
424
579
 
425
- ## 📄 License
580
+ asyncHandlers: {
581
+ login: async (state, email: string, password: string) => {
582
+ state.isLoading = true;
583
+
584
+ try {
585
+ const response = await fetch("/api/login", {
586
+ method: "POST",
587
+ headers: { "Content-Type": "application/json" },
588
+ body: JSON.stringify({ email, password }),
589
+ });
590
+
591
+ const data = await response.json();
592
+
593
+ state.user = data.user;
594
+ state.isAuthenticated = true;
595
+ } catch (error) {
596
+ console.error("Login failed:", error);
597
+ } finally {
598
+ state.isLoading = false;
599
+ }
600
+ },
426
601
 
427
- MIT © [Your Name]
602
+ logout: async (state) => {
603
+ await fetch("/api/logout", { method: "POST" });
604
+ state.user = null;
605
+ state.isAuthenticated = false;
606
+ },
607
+ },
608
+ });
609
+ ```
610
+
611
+ ## 🎓 TypeScript Support
612
+
613
+ The library works great with TypeScript! You get autocomplete and type safety.
614
+
615
+ ### Defining State Types
616
+
617
+ ```tsx
618
+ // Define your state shape
619
+ type UserState = {
620
+ name: string;
621
+ age: number;
622
+ email: string;
623
+ };
624
+
625
+ const store = createStore({
626
+ states: {
627
+ count: 0,
628
+ user: {
629
+ name: "John",
630
+ age: 25,
631
+ email: "john@example.com",
632
+ } as UserState,
633
+ },
634
+
635
+ syncHandlers: {
636
+ // TypeScript knows the state type!
637
+ updateUser: (state, newUser: UserState) => {
638
+ state.user = newUser;
639
+ },
640
+ },
641
+ });
642
+
643
+ // TypeScript will catch errors
644
+ const handlers = store.useHandlers();
645
+ handlers.updateUser({
646
+ name: "Jane",
647
+ age: 26,
648
+ // ❌ Error: missing 'email' property
649
+ });
650
+ ```
651
+
652
+ ## ❓ Common Questions
653
+
654
+ ### Q: When should I use a global store vs provider?
655
+
656
+ **Use Global Store (`createStore`) when:**
657
+
658
+ - Data is needed across your entire app (like user auth, theme)
659
+ - You want simple setup without wrapping components
660
+
661
+ **Use Provider (`createStoreProvider`) when:**
662
+
663
+ - Data is only needed in a specific section
664
+ - You want better component isolation
665
+ - You're building reusable components
666
+
667
+ ### Q: How is this different from useState?
668
+
669
+ `useState` is great for local component state. Use `@fun-tools/store` when:
670
+
671
+ - Multiple components need the same data
672
+ - You want to avoid prop drilling
673
+ - You need more powerful update functions
674
+
675
+ ### Q: Can I use multiple stores?
676
+
677
+ Yes! Create as many stores as you need:
678
+
679
+ ```tsx
680
+ const userStore = createStore({ states: { user: null } });
681
+ const cartStore = createStore({ states: { items: [] } });
682
+ const themeStore = createStore({ states: { theme: "light" } });
683
+ ```
684
+
685
+ ## 🤝 Contributors
686
+
687
+ This project is open source and welcomes contributions from the community! We appreciate all the developers who have helped make this library better.
688
+
689
+ ### How to Contribute
690
+
691
+ We welcome contributions of all kinds:
692
+
693
+ - 🐛 Bug fixes
694
+ - ✨ New features
695
+ - 📝 Documentation improvements
696
+ - 💡 Suggestions and ideas
697
+
698
+ To contribute:
699
+
700
+ 1. Fork the repository
701
+ 2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
702
+ 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
703
+ 4. Push to the branch (`git push origin feature/AmazingFeature`)
704
+ 5. Open a Pull Request
705
+
706
+ ### Our Contributors
707
+
708
+ Thanks to all the amazing people who have contributed to this project! 🎉
709
+
710
+ <!-- Contributors list will be automatically updated -->
711
+
712
+ Want to see your name here? [Start contributing today!](https://github.com/fun-tools24/fun-tools-store/contribute)
428
713
 
429
714
  ## 🔗 Links
430
715
 
431
- - [GitHub Repository](https://github.com/yourusername/ex-store)
432
- - [Issues](https://github.com/yourusername/ex-store/issues)
716
+ - [GitHub Repository](https://github.com/fun-tools24/fun-tools-store)
717
+ - [Report Issues](https://github.com/fun-tools24/fun-tools-store/issues)
433
718
  - [NPM Package](https://www.npmjs.com/package/@fun-tools/store)
434
719
 
435
720
  ---
436
721
 
437
- Made with ❤️ by developers, for developers
722
+ **Made with ❤️ for developers who value simplicity by @fun-tools24**
723
+
724
+ Happy coding! 🚀