cogsbox-state 0.5.7 → 0.5.9

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.
Files changed (2) hide show
  1. package/README.md +521 -279
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,386 +1,628 @@
1
- # Cobgsbox State
1
+ # Cogsbox State: A Practical Guide
2
2
 
3
- > ⚠️ **Warning**: This package is currently a work in progress and not ready for production use. The API is unstable and subject to breaking changes. Please do not use in production environments.
3
+ > **⚠️ WARNING**: This README is AI-generated based on the current implementation of Cogsbox State. The library is under active development and APIs are subject to change. Always refer to the official documentation or source code for the most up-to-date information.
4
4
 
5
- ---
5
+ ## Getting Started
6
6
 
7
- Cobgsbox State is a state management library that provides a fluent interface for managing complex state in React applications.
7
+ Cogsbox State is a React state management library that provides a fluent interface for managing complex state.
8
8
 
9
- ## Installation
9
+ ### Basic Setup
10
10
 
11
- ```bash
12
- npm install cogsbox-state
13
- ```
14
-
15
- ## Features
16
-
17
- - 🎯 **Simplified Deep Updates**
18
-
19
- ```typescript
20
- // Instead of setState(prev => ({ ...prev, deep: { ...prev.deep, value: newValue }}))
21
- updater.deep.value.update(newValue);
22
- ```
23
-
24
- - 🔄 **Fluent Array Operations**
25
-
26
- ```typescript
27
- // Find, filter, and update in one chain
28
- updater.items.findWith("id", "123").status.update("complete");
29
- ```
30
-
31
- - 📝 **Smart Form Handling**
32
-
33
- - Automatic debouncing
34
- - Validation integration
35
- - Form state synchronization
36
-
37
- - 🔍 **Powerful Array Methods**
11
+ ```typescript
12
+ // 1. Define your initial state
13
+ const InitialState = {
14
+ users: [],
15
+ settings: {
16
+ darkMode: false,
17
+ notifications: true
18
+ },
19
+ cart: {
20
+ items: [],
21
+ total: 0
22
+ }
23
+ };
38
24
 
39
- - Filter with state access
40
- - Flatten nested arrays
41
- - Unique insertions
42
- - Map with updaters
25
+ // 2. Create the state hook
26
+ export const { useCogsState } = createCogsState(InitialState);
43
27
 
44
- - 🔄 **State Sync Features**
28
+ // 3. Use in your component
29
+ function MyComponent() {
30
+ const cart = useCogsState("cart");
45
31
 
46
- - Server synchronization
47
- - Local storage persistence
48
- - Optimistic updates
32
+ // Access values
33
+ const cartItems = cart.items.get();
34
+ const total = cart.total.get();
49
35
 
50
- - 🛠 **Developer Experience**
36
+ // Update values
37
+ const addItem = (item) => {
38
+ cart.items.insert(item);
39
+ cart.total.update(total + item.price);
40
+ };
51
41
 
52
- - Full TypeScript support
53
- - Path autocompletion
54
- - Runtime type checking
42
+ return (
43
+ // Your component JSX
44
+ );
45
+ }
46
+ ```
55
47
 
56
- - **Performance**
57
- - Granular updates
58
- - Automatic optimization
59
- - Path-based subscriptions
48
+ ## Core Concepts
60
49
 
61
- ## Initialization
50
+ ### Accessing State
62
51
 
63
52
  ```typescript
64
- // Define your state shape
65
- interface Product {
66
- id: string;
67
- name: string;
68
- price: number;
69
- categories: string[];
70
- variants: {
71
- id: string;
72
- color: string;
73
- size: string;
74
- stock: number;
75
- }[];
76
- }
77
-
78
- interface CartItem {
79
- productId: string;
80
- variantId: string;
81
- quantity: number;
82
- }
83
-
84
- const InitialState = {
85
- catalog: {
86
- products: [] as Product[],
87
- categories: [] as string[],
88
- filters: {
89
- priceRange: { min: 0, max: 100 },
90
- selectedCategories: [] as string[],
91
- search: "",
92
- },
93
- sortBy: "price_asc" as "price_asc" | "price_desc" | "name",
94
- },
95
- cart: {
96
- items: [] as CartItem[],
97
- couponCode: "",
98
- shipping: {
99
- address: "",
100
- method: "standard" as "standard" | "express",
101
- cost: 0,
102
- },
103
- },
104
- ui: {
105
- sidebarOpen: false,
106
- activeProductId: null as string | null,
107
- notifications: [] as {
108
- id: string;
109
- message: string;
110
- type: "success" | "error";
111
- }[],
112
- },
113
- };
53
+ // Get the entire state object
54
+ const entireCart = cart.get();
114
55
 
115
- // Create state hook
116
- export const { useCogsState } = createCogsState(InitialState);
56
+ // Access a specific property
57
+ const cartItems = cart.items.get();
117
58
 
118
- // Use in component
119
- const [state, updater] = useCogsState("catalog");
59
+ // Access nested properties
60
+ const firstItemPrice = cart.items.index(0).price.get();
120
61
  ```
121
62
 
122
- ## Updater API
123
-
124
- ### Basic Updates
125
-
126
- #### `.update()`
127
-
128
- Updates state value directly.
63
+ ### Updating State
129
64
 
130
65
  ```typescript
131
66
  // Direct update
132
- updater.catalog.filters.search.update("blue shoes");
67
+ cart.settings.darkMode.update(true);
133
68
 
134
- // Functional update
135
- updater.cart.items[0].quantity.update((prev) => prev + 1);
69
+ // Functional update (based on previous value)
70
+ cart.cart.total.update((prev) => prev + 10);
136
71
 
137
72
  // Deep update
138
- updater.catalog.products
139
- .findWith("id", "123")
140
- .variants[0].stock.update((prev) => prev - 1);
73
+ cart.users.findWith("id", "123").name.update("New Name");
141
74
  ```
142
75
 
143
- #### `.get()`
76
+ ## Working with Arrays
144
77
 
145
- Gets current state value.
78
+ ### Basic Array Operations
146
79
 
147
80
  ```typescript
148
- const searchTerm = updater.catalog.filters.search.get();
149
- const cartTotal = updater.cart.items
150
- .get()
151
- .reduce((sum, item) => sum + item.quantity, 0);
152
- ```
81
+ // Add an item
82
+ cart.cart.items.insert({ id: "prod1", name: "Product 1", price: 29.99 });
83
+
84
+ // Remove an item at index
85
+ cart.cart.items.cut(2);
153
86
 
154
- ### Array Operations
87
+ // Find and update an item
88
+ cart.cart.items.findWith("id", "prod1").quantity.update((prev) => prev + 1);
155
89
 
156
- #### `.insert()`
90
+ // Update item at specific index
91
+ cart.cart.items.index(0).price.update(19.99);
92
+ ```
157
93
 
158
- Inserts an item into an array.
94
+ ### Advanced Array Methods
159
95
 
160
96
  ```typescript
161
- // Add product
162
- updater.catalog.products.insert({
163
- id: "123",
164
- name: "Running Shoes",
165
- price: 99.99,
166
- categories: ["shoes", "sports"],
167
- variants: [],
168
- });
97
+ // Map with access to updaters
98
+ cart.cart.items.stateMap((item, itemUpdater) => (
99
+ <CartItem
100
+ key={item.id}
101
+ item={item}
102
+ onQuantityChange={qty => itemUpdater.quantity.update(qty)}
103
+ />
104
+ ));
105
+
106
+ // Filter items while maintaining updater capabilities
107
+ const inStockItems = cart.products.stateFilter(product => product.stock > 0);
108
+
109
+ // Insert only if the item doesn't exist
110
+ cart.cart.items.uniqueInsert(
111
+ { id: "prod1", quantity: 1 },
112
+ ["id"] // fields to check for uniqueness
113
+ );
169
114
 
170
- // Add to cart
171
- updater.cart.items.insert((prev) => ({
172
- productId: "123",
173
- variantId: "v1",
174
- quantity: 1,
175
- }));
115
+ // Flatten nested arrays by property
116
+ const allVariants = cart.products.stateFlattenOn("variants");
176
117
  ```
177
118
 
178
- #### `.uniqueInsert()`
119
+ ## Reactivity Control
120
+
121
+ Cogsbox offers different ways to control when components re-render:
179
122
 
180
- Inserts only if item doesn't exist (checks deep equality).
123
+ ### Component Reactivity (Default)
124
+
125
+ Re-renders when any accessed value changes.
181
126
 
182
127
  ```typescript
183
- // Add category if not exists
184
- updater.catalog.categories.uniqueInsert("sports");
185
-
186
- // Add notification with unique ID
187
- updater.ui.notifications.uniqueInsert(
188
- {
189
- id: generateId(),
190
- message: "Item added to cart",
191
- type: "success",
192
- },
193
- ["id"],
128
+ // Default behavior - re-renders when cart.items or cart.total changes
129
+ const cart = useCogsState("cart");
130
+
131
+ return (
132
+ <div>
133
+ <div>Items: {cart.items.get().length}</div>
134
+ <div>Total: {cart.total.get()}</div>
135
+ </div>
194
136
  );
195
137
  ```
196
138
 
197
- #### `.cut()`
139
+ ### Dependency-Based Reactivity
198
140
 
199
- Removes an item from an array.
141
+ Re-renders only when specified dependencies change.
200
142
 
201
143
  ```typescript
202
- // Remove from cart
203
- updater.cart.items.cut(index);
204
-
205
- // Remove notification
206
- updater.ui.notifications.findWith("id", "notif-123").cut();
144
+ // Only re-renders when items array or status changes
145
+ const cart = useCogsState("cart", {
146
+ reactiveType: ["deps"],
147
+ reactiveDeps: (state) => [state.items, state.status],
148
+ });
207
149
  ```
208
150
 
209
- #### `.findWith()`
151
+ ### Full Reactivity
210
152
 
211
- Finds an item in array by property comparison.
153
+ Re-renders on any state change, even for unused properties.
212
154
 
213
155
  ```typescript
214
- // Find and update product
215
- updater.catalog.products.findWith("id", 123).price.update(99.99);
216
-
217
- // Find and update cart item
218
- updater.cart.items
219
- .findWith("productId", 123)
220
- .quantity.update((prev) => prev + 1);
156
+ // Re-renders on any change to cart state
157
+ const cart = useCogsState("cart", {
158
+ reactiveType: ["all"],
159
+ });
221
160
  ```
222
161
 
223
- #### `.index()`
162
+ ### Signal-Based Reactivity
224
163
 
225
- Gets item at specific index with updater methods.
164
+ Updates only the DOM elements that depend on changed values.
226
165
 
227
166
  ```typescript
228
- // Update first cart item
229
- updater.cart.items.index(0).quantity.update(2);
167
+ // Most efficient - updates just the specific DOM elements
168
+ return (
169
+ <div>
170
+ <div>Items: {cart.items.$derive(items => items.length)}</div>
171
+ <div>Total: {cart.total.$get()}</div>
172
+ </div>
173
+ );
230
174
  ```
231
175
 
232
- #### `.stateEach()`
176
+ ## Form Integration
177
+
178
+ Cogsbox State provides an intuitive form system to connect your state to form controls with built-in validation, error handling, and array support.
233
179
 
234
- Maps over array with access to item updater.
180
+ ### Basic Form Element Usage
181
+
182
+ The `formElement` method serves as the bridge between state and UI:
235
183
 
236
184
  ```typescript
237
- // Apply discount to all products
238
- updater.catalog.products.stateEach((product, productUpdater) => {
239
- productUpdater.price.update((price) => price * 0.9);
240
- });
185
+ // Direct value/onChange pattern for complete control
186
+ user.firstName.formElement((params) => (
187
+ <div>
188
+ <label className="block text-sm font-medium">First Name</label>
189
+ <input
190
+ type="text"
191
+ className="mt-1 block w-full rounded-md border-2 p-2"
192
+ value={params.get()}
193
+ onChange={(e) => params.set(e.target.value)}
194
+ onBlur={params.inputProps.onBlur}
195
+ ref={params.inputProps.ref}
196
+ />
197
+ </div>
198
+ ));
199
+
200
+ // Using inputProps shorthand for simpler binding
201
+ user.lastName.formElement((params) => (
202
+ <div>
203
+ <label className="block text-sm font-medium">Last Name</label>
204
+ <input
205
+ type="text"
206
+ className="mt-1 block w-full rounded-md border-2 p-2"
207
+ {...params.inputProps}
208
+ />
209
+ </div>
210
+ ));
241
211
  ```
242
212
 
243
- #### `.stateFilter()`
213
+ ### Form Validation Options
244
214
 
245
- Creates filtered view of array with updater methods.
215
+ Cogsbox provides several approaches to validation:
246
216
 
247
217
  ```typescript
248
- // Get low stock variants
249
- const lowStock = updater.catalog.products.stateFilter((product) =>
250
- product.variants.some((v) => v.stock < 5),
218
+ // Custom validation message
219
+ user.email.formElement(
220
+ (params) => (
221
+ <div>
222
+ <label>Email Address</label>
223
+ <input {...params.inputProps} type="email" />
224
+ </div>
225
+ ),
226
+ {
227
+ validation: {
228
+ message: "Please enter a valid email address"
229
+ }
230
+ }
251
231
  );
252
232
 
253
- // Update prices for filtered products
254
- lowStock.stateEach((product, productUpdater) => {
255
- productUpdater.price.update((price) => price * 0.8);
256
- });
233
+ // Hidden validation (show border but no message)
234
+ user.lastName.formElement(
235
+ (params) => (
236
+ <div>
237
+ <label>Last Name</label>
238
+ <input
239
+ {...params.inputProps}
240
+ className={`input ${params.validationErrors().length > 0 ? 'border-red-500' : ''}`}
241
+ />
242
+ </div>
243
+ ),
244
+ {
245
+ validation: {
246
+ hideMessage: true
247
+ }
248
+ }
249
+ );
250
+
251
+ // Custom validation with onBlur
252
+ user.phone.formElement((params) => (
253
+ <div>
254
+ <label>Phone Number</label>
255
+ <input
256
+ {...params.inputProps}
257
+ onBlur={(e) => {
258
+ if (e.target.value.length == 0 || isNaN(Number(e.target.value))) {
259
+ params.addValidationError("Please enter a valid phone number");
260
+ }
261
+ }}
262
+ placeholder="(555) 123-4567"
263
+ />
264
+ </div>
265
+ ));
257
266
  ```
258
267
 
259
- #### `.stateFlattenOn()`
268
+ ### Working with Form Arrays
260
269
 
261
- Flattens nested arrays by property.
270
+ For managing collections like addresses:
262
271
 
263
272
  ```typescript
264
- // Get all variants across products
265
- const allVariants = updater.catalog.products.stateFlattenOn("variants");
266
- ```
273
+ function AddressesManager() {
274
+ const [currentAddressIndex, setCurrentAddressIndex] = useState(0);
275
+ const user = useCogsState("user");
276
+
277
+ // Add new address
278
+ const addNewAddress = () => {
279
+ user.addresses.insert({
280
+ street: "",
281
+ city: "",
282
+ state: "",
283
+ zipCode: "",
284
+ country: "USA",
285
+ isDefault: false,
286
+ });
287
+ setCurrentAddressIndex(user.addresses.get().length - 1);
288
+ };
267
289
 
268
- ### Form Integration
290
+ return (
291
+ <div>
292
+ {/* Address tabs with validation indicators */}
293
+ <div className="flex space-x-2 mt-2">
294
+ {user.addresses.stateMap((_, setter, index) => {
295
+ const errorCount = setter.showValidationErrors().length;
296
+ return (
297
+ <button
298
+ key={index}
299
+ onClick={() => setCurrentAddressIndex(index)}
300
+ className={`rounded-lg flex items-center justify-center ${
301
+ errorCount > 0
302
+ ? "border-red-500 bg-red-400"
303
+ : currentAddressIndex === index
304
+ ? "bg-blue-500 text-white"
305
+ : "bg-gray-200"
306
+ }`}
307
+ >
308
+ {index + 1}
309
+ {errorCount > 0 && (
310
+ <div className="bg-red-500 text-white rounded-full">
311
+ {errorCount}
312
+ </div>
313
+ )}
314
+ </button>
315
+ );
316
+ })}
317
+ <button onClick={addNewAddress}>Add</button>
318
+ </div>
319
+
320
+ {/* Current address form */}
321
+ {user.addresses.get().length > 0 && (
322
+ <div className="grid grid-cols-1 gap-4">
323
+ {/* Access fields with index() method */}
324
+ {user.addresses.index(currentAddressIndex).street.formElement(
325
+ (params) => (
326
+ <div>
327
+ <label>Street</label>
328
+ <input value={params.get()} onChange={(e) => params.set(e.target.value)} />
329
+ </div>
330
+ ),
331
+ {
332
+ validation: {
333
+ message: "Street address is required"
334
+ }
335
+ }
336
+ )}
337
+
338
+ {/* City and State in a row */}
339
+ <div className="grid grid-cols-2 gap-4">
340
+ {user.addresses.index(currentAddressIndex).city.formElement((params) => (
341
+ <div>
342
+ <label>City</label>
343
+ <input {...params.inputProps} />
344
+ </div>
345
+ ))}
346
+
347
+ {user.addresses.index(currentAddressIndex).state.formElement((params) => (
348
+ <div>
349
+ <label>State</label>
350
+ <input {...params.inputProps} />
351
+ </div>
352
+ ))}
353
+ </div>
354
+
355
+ {/* Boolean field handling */}
356
+ {user.addresses.index(currentAddressIndex).isDefault.formElement((params) => (
357
+ <div className="flex items-center">
358
+ <input
359
+ type="checkbox"
360
+ checked={params.get()}
361
+ onChange={(e) => params.set(e.target.checked)}
362
+ id={`default-address-${currentAddressIndex}`}
363
+ />
364
+ <label htmlFor={`default-address-${currentAddressIndex}`}>
365
+ Set as default address
366
+ </label>
367
+ </div>
368
+ ))}
369
+
370
+ {/* Remove address button */}
371
+ {user.addresses.get().length > 1 && (
372
+ <button
373
+ onClick={() => {
374
+ user.addresses.cut(currentAddressIndex);
375
+ setCurrentAddressIndex(Math.max(0, currentAddressIndex - 1));
376
+ }}
377
+ >
378
+ Remove Selected Address
379
+ </button>
380
+ )}
381
+ </div>
382
+ )}
383
+ </div>
384
+ );
385
+ }
386
+ ```
269
387
 
270
- #### `.formElement()`
388
+ ### Form Actions
271
389
 
272
- Creates form control with validation.
390
+ Cogsbox provides methods to manage form state:
273
391
 
274
392
  ```typescript
275
- updater.cart.shipping.address.formElement("shipping", ({ inputProps }) => (
276
- <input {...inputProps} placeholder="Shipping address" />
277
- ), {
278
- validation: {
279
- message: "Address is required",
280
- onChange: { clear: ["shipping.address"] }
281
- },
282
- debounceTime: 300
283
- })
393
+ // Reset form to initial state
394
+ const handleReset = () => {
395
+ user.revertToInitialState();
396
+ };
397
+
398
+ // Validate all fields using Zod schema
399
+ const handleSubmit = () => {
400
+ if (user.validateZodSchema()) {
401
+ // All valid, proceed with submission
402
+ submitData(user.get());
403
+ }
404
+ };
284
405
  ```
285
406
 
286
- ### Menu & Selection API
407
+ ### Setting Up Zod Validation
287
408
 
288
- #### `.setSelected()`
409
+ ```typescript
410
+ // Setting up validation at initialization
411
+ export const { useCogsState } = createCogsState({
412
+ user: {
413
+ initialState: {
414
+ firstName: "",
415
+ lastName: "",
416
+ email: "",
417
+ phone: "",
418
+ addresses: [
419
+ {
420
+ street: "",
421
+ city: "",
422
+ state: "",
423
+ zipCode: "",
424
+ country: "USA",
425
+ isDefault: false,
426
+ },
427
+ ],
428
+ },
429
+ validation: {
430
+ key: "userForm", // Used for error tracking
431
+ zodSchema: z.object({
432
+ firstName: z.string().min(1, "First name is required"),
433
+ lastName: z.string().min(1, "Last name is required"),
434
+ email: z.string().email("Please enter a valid email"),
435
+ phone: z.string().min(10, "Phone number must be at least 10 digits"),
436
+ addresses: z.array(
437
+ z.object({
438
+ street: z.string().min(1, "Street is required"),
439
+ city: z.string().min(1, "City is required"),
440
+ state: z.string().min(1, "State is required"),
441
+ zipCode: z
442
+ .string()
443
+ .min(5, "Zip code must be at least 5 characters"),
444
+ country: z.string(),
445
+ isDefault: z.boolean(),
446
+ })
447
+ ),
448
+ }),
449
+ },
450
+ },
451
+ });
452
+ ```
289
453
 
290
- Marks an item as selected in a list.
454
+ ## Server Synchronization
291
455
 
292
456
  ```typescript
293
- // Select product
294
- updater.catalog.products[0].setSelected(true);
457
+ // Setting up server sync
458
+ const products = useCogsState("products", {
459
+ serverSync: {
460
+ syncKey: "products",
461
+ syncFunction: ({ state }) => api.updateProducts(state),
462
+ debounce: 1000, // ms
463
+ mutation: useMutation(api.updateProducts),
464
+ },
465
+ });
295
466
 
296
- // Select category
297
- updater.catalog.categories.findWith("name", "sports").setSelected(true);
467
+ // State is automatically synced with server after changes
468
+ products.items.index(0).stock.update((prev) => prev - 1);
298
469
  ```
299
470
 
300
- #### `.getSelected()`
301
-
302
- Gets currently selected item from a list.
471
+ ## Local Storage Persistence
303
472
 
304
473
  ```typescript
305
- const selectedProduct = updater.catalog.products.getSelected();
474
+ // Automatically save state to localStorage
475
+ const cart = useCogsState("cart", {
476
+ localStorage: {
477
+ key: "shopping-cart",
478
+ },
479
+ });
306
480
  ```
307
481
 
308
- [Rest of documentation remains the same...]
309
-
310
- ## Examples
311
-
312
- ### Product Catalog Management
482
+ ## Example: Shopping Cart
313
483
 
314
484
  ```typescript
315
- function ProductList() {
316
- const [state, updater] = useCogsState("catalog", {
317
- serverSync: {
318
- syncKey: "products",
319
- syncFunction: async ({ state }) => {
320
- await api.updateProducts(state.products)
321
- }
322
- }
323
- });
324
-
325
- const filteredProducts = updater.products
326
- .stateFilter(product =>
327
- product.price >= state.filters.priceRange.min &&
328
- product.price <= state.filters.priceRange.max &&
329
- (state.filters.selectedCategories.length === 0 ||
330
- product.categories.some(c => state.filters.selectedCategories.includes(c)))
485
+ function ShoppingCart() {
486
+ const cart = useCogsState("cart");
487
+ const products = useCogsState("products");
488
+
489
+ const addToCart = (productId) => {
490
+ const product = products.items.findWith("id", productId).get();
491
+
492
+ cart.items.uniqueInsert(
493
+ {
494
+ productId,
495
+ name: product.name,
496
+ price: product.price,
497
+ quantity: 1
498
+ },
499
+ ["productId"],
500
+ // If product exists, update quantity instead
501
+ (existingItem) => ({
502
+ ...existingItem,
503
+ quantity: existingItem.quantity + 1
504
+ })
331
505
  );
332
506
 
507
+ // Update total
508
+ cart.total.update(prev => prev + product.price);
509
+ };
510
+
333
511
  return (
334
512
  <div>
335
- {filteredProducts.stateEach((product, productUpdater) => (
336
- <ProductCard
337
- key={product.id}
338
- product={product}
339
- onUpdateStock={(variantId, newStock) =>
340
- productUpdater
341
- .variants
342
- .findWith("id", variantId)
343
- .stock
344
- .update(newStock)
345
- }
346
- />
513
+ <h2>Your Cart</h2>
514
+
515
+ {cart.items.stateMap((item, itemUpdater) => (
516
+ <div key={item.productId} className="cart-item">
517
+ <div>{item.name}</div>
518
+ <div>${item.price}</div>
519
+
520
+ <div className="quantity">
521
+ <button onClick={() =>
522
+ itemUpdater.quantity.update(prev => Math.max(prev - 1, 0))
523
+ }>-</button>
524
+
525
+ <span>{item.quantity}</span>
526
+
527
+ <button onClick={() =>
528
+ itemUpdater.quantity.update(prev => prev + 1)
529
+ }>+</button>
530
+ </div>
531
+
532
+ <button onClick={() => itemUpdater.cut()}>Remove</button>
533
+ </div>
347
534
  ))}
535
+
536
+ <div className="cart-total">
537
+ <strong>Total:</strong> ${cart.total.get()}
538
+ </div>
348
539
  </div>
349
540
  );
350
541
  }
351
542
  ```
352
543
 
353
- ### Shopping Cart Management
544
+ ## Session Support
354
545
 
355
- ```typescript
356
- function CartManager() {
357
- const [state, updater] = useCogsState("cart", {
358
- localStorage: {
359
- key: "shopping-cart"
360
- }
361
- });
362
-
363
- const addToCart = (product: Product, variantId: string) => {
364
- updater.items.uniqueInsert({
365
- productId: product.id,
366
- variantId,
367
- quantity: 1
368
- }, ['productId', 'variantId']);
369
- };
546
+ Cogsbox State supports session-based state management through the `useCogsConfig` hook, allowing you to isolate state for different user sessions:
370
547
 
371
- return (
372
- <div>
373
- {updater.items.stateEach((item, itemUpdater) => (
374
- <CartItem
375
- key={item.productId}
376
- item={item}
377
- onUpdateQuantity={qty => itemUpdater.quantity.update(qty)}
378
- onRemove={() => itemUpdater.cut()}
379
- />
380
- ))}
381
- </div>
382
- );
383
- }
548
+ ```typescript
549
+ // Using session-specific state
550
+ const cart = useCogsState("cart", {
551
+ localStorageKey: "user-cart", // Will be prefixed with sessionId
552
+ initState: {
553
+ initialState: {
554
+ items: [],
555
+ total: 0,
556
+ },
557
+ },
558
+ });
384
559
  ```
385
560
 
386
- [Rest of TypeScript section remains the same...]
561
+ ## Performance Optimizations
562
+
563
+ The library includes several performance optimizations:
564
+
565
+ 1. **Cache Management**: Cogsbox maintains a cache of proxy objects to reduce re-creation overhead.
566
+ 2. **Batched Updates**: State updates are batched where possible to minimize render cycles.
567
+ 3. **Signal-based DOM Updates**: Directly update DOM elements without re-rendering components.
568
+
569
+ ## Common Patterns and Tips
570
+
571
+ 1. **Path-based Updates**: Always use the fluent API to update nested properties.
572
+
573
+ ```typescript
574
+ // Good
575
+ user.users.index(0).address.city.update("New York");
576
+
577
+ // Avoid
578
+ user.update({ ...state, users: [...] });
579
+ ```
580
+
581
+ 2. **Working with Arrays**: Use the built-in array methods instead of manually updating array state.
582
+
583
+ ```typescript
584
+ // Good
585
+ user.users.insert(newUser);
586
+ user.users.findWith("id", 123).active.update(true);
587
+
588
+ // Avoid
589
+ user.users.update([...users, newUser]);
590
+ ```
591
+
592
+ 3. **Optimization**: Use the appropriate reactivity type for your needs.
593
+
594
+ ```typescript
595
+ // For lists where only specific items change frequently
596
+ user.items.stateMap((item) => (
597
+ <div>{item.$get()}</div> // Only this item re-renders when changed
598
+ ));
599
+ ```
600
+
601
+ 4. **Form Management**: Use formElement for all form inputs to get automatic validation and debouncing.
602
+
603
+ ```typescript
604
+ profile.name.formElement(
605
+ ({ inputProps }) => <input {...inputProps} />,
606
+ { debounceTime: 300 }
607
+ );
608
+ ```
609
+
610
+ 5. **Middleware Support**: Add middleware for logging, analytics, or custom state processing:
611
+
612
+ ```typescript
613
+ const user = useCogsState("user", {
614
+ middleware: ({ update, updateLog }) => {
615
+ // Log all state changes
616
+ console.log("State update:", update);
617
+
618
+ // Trigger analytics
619
+ if (update.path.includes("preferences")) {
620
+ analytics.track("preferences_changed", update.newValue);
621
+ }
622
+ },
623
+ });
624
+ ```
625
+
626
+ ## API Reference
627
+
628
+ For a comprehensive API reference, see the TypeScript interfaces and examples in the source code.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cogsbox-state",
3
- "version": "0.5.7",
3
+ "version": "0.5.9",
4
4
  "description": "React state management library with form controls and server sync",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",