cogsbox-state 0.5.431 → 0.5.434

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,361 +1,719 @@
1
- # Cogsbox State: A Practical Guide
1
+ # Cogsbox State: A Comprehensive Guide
2
2
 
3
3
  > **🚨 DANGER: DO NOT USE - UNSTABLE & EXPERIMENTAL 🚨**
4
4
  >
5
5
  > This library is in extremely early development and constantly changing.
6
- > Everything will break. Nothing works properly.
7
- > **DO NOT USE IN ANY PROJECT.**
6
+ >
7
+ > **DO NOT USE IN ANY PROJECT YET - ONLY FOR TESTING AND PROVIDING FEEDBACK.**
8
8
 
9
- ## Getting Started
9
+ ## What is Cogsbox State?
10
10
 
11
- Cogsbox State is a React state management library that provides a fluent, chainable interface for managing complex state. It's designed to make deep updates and form management intuitive and simple.
11
+ Cogsbox State is a React state management library that creates a **nested state builder** - a type-safe proxy that mimics your initial state structure. Every property in your state becomes a powerful state object with built-in methods for updates, arrays, forms, and more.
12
12
 
13
- ### Basic Setup
13
+ **Key Philosophy**: Instead of complex useState drilling and manual mapping, you directly access nested properties and use built-in methods.
14
14
 
15
- 1. **Define your initial state configuration.**
16
- It's best practice to structure each state slice with its own `initialState` and `options`.
15
+ ## Getting Started
16
+
17
+ ### Basic Setup
17
18
 
18
19
  ```typescript
19
- // 1. Define your initial state
20
- const InitialState = {
21
- // A simple slice for app settings
22
- settings: {
23
- initialState: {
24
- darkMode: false,
25
- notifications: true,
26
- username: "Guest",
27
- },
28
- },
29
- // A more complex slice for a shopping cart
30
- cart: {
31
- initialState: {
32
- items: [], // Array of { id, name, price, quantity }
33
- total: 0,
34
- status: "active",
20
+ import { createCogsState } from 'cogsbox-state';
21
+
22
+ // 1. Define your initial state structure
23
+ const initialState = {
24
+ user: {
25
+ name: "John",
26
+ stats: {
27
+ counter: 0,
28
+ lastUpdated: null
35
29
  },
30
+ age: 30,
31
+ online:false
36
32
  },
33
+ todos: [],
34
+ settings: {
35
+ darkMode: false,
36
+ notifications: true
37
+ }
37
38
  };
38
39
 
39
- // 2. Create the state hook
40
- export const { useCogsState } = createCogsState(InitialState);
41
- ```
42
-
43
- 2. **Use the hook in your components.**
44
-
45
- ```typescript
46
- // 3. Use in your component
47
- function SettingsPanel() {
48
- // Access the "settings" state slice
49
- const settings = useCogsState("settings");
40
+ // 2. Create your state manager
41
+ const { useCogsState } = createCogsState(initialState);
50
42
 
51
- // Read a value
52
- const isDarkMode = settings.darkMode.get();
43
+ // 3. Use in components - access specific state slices by their keys
44
+ function UserComponent() {
45
+ const user = useCogsState('user'); // Access the 'user' slice
53
46
 
54
- // Update a value
55
- const toggleDarkMode = () => {
56
- settings.darkMode.update(prev => !prev);
57
- };
58
-
59
- // Update another value
60
- const handleUsernameChange = (e) => {
61
- settings.username.update(e.target.value);
47
+ return (
48
+ <div>
49
+ <p>Name: {user.name.get()}</p>
50
+ <p>Counter: {user.stats.counter.get()}</p>
51
+ <button onClick={() => user.stats.counter.update(prev => prev + 1)}>
52
+ Increment Counter
53
+ </button>
54
+ </div>
55
+ );
62
56
  }
63
57
 
64
- return (
65
- <div>
66
- <p>User: {settings.username.get()}</p>
67
- <button onClick={toggleDarkMode}>
68
- Toggle Dark Mode ({isDarkMode ? "On" : "Off"})
69
- </button>
70
- </div>
71
- );
58
+ function TodoComponent() {
59
+ const todos = useCogsState('todos'); // Access the 'todos' slice
60
+
61
+ return (
62
+ <div>
63
+ <p>Todo count: {todos.get().length}</p>
64
+ <button onClick={() => todos.insert({ id: Date.now(), text: 'New todo', done: false })}>
65
+ Add Todo
66
+ </button>
67
+ </div>
68
+ );
72
69
  }
73
70
  ```
74
71
 
75
72
  ## Core Concepts
76
73
 
77
- ### Accessing State
74
+ ### State Access Patterns
78
75
 
79
- Reading state is always done by calling `.get()` at the end of a chain.
76
+ Every state property gets these core methods:
80
77
 
81
- ```typescript
82
- const settings = useCogsState("settings");
78
+ #### Primitives (strings, numbers, booleans)
79
+
80
+ - `.get()` - read values reactively
81
+ - `.update()` - set values
82
+ - `.toggle()` - flip booleans
83
+ - `.$get()` - non-reactive read (signals)
84
+ - `.$derive()` - computed signals
85
+
86
+ #### Objects
87
+
88
+ - All primitive methods plus access to nested properties
89
+ - `.update()` can do partial updates
90
+
91
+ #### Arrays
92
+
93
+ - All core methods plus array-specific operations
94
+ - Built-in selection tracking and metadata
83
95
 
84
- // Get the entire 'settings' object
85
- const allSettings = settings.get();
96
+ ### Reading State
86
97
 
87
- // Access a specific property
98
+ ```typescript
99
+ const user = useCogsState('user');
100
+ const todos = useCogsState('todos');
101
+ const settings = useCogsState('settings');
102
+
103
+ // Reactive reads (triggers re-renders)
104
+ const userName = user.name.get();
105
+ const allTodos = todos.get();
88
106
  const isDarkMode = settings.darkMode.get();
89
107
 
90
- // For arrays, access elements by index
91
- const firstItem = cart.items.index(0).get();
108
+ // Access nested properties
109
+ const counterValue = user.stats.counter.get();
110
+ const firstTodo = todos.index(0)?.get();
111
+
112
+ // Non-reactive reads (no re-renders, for signals)
113
+ const userNameStatic = user.name.$get();
92
114
 
93
- // Chain deeper for nested properties
94
- const firstItemPrice = cart.items.index(0).price.get();
115
+ // Computed signals (transforms value without re-renders)
116
+ const todoCount = todos.$derive((todos) => todos.length);
95
117
  ```
96
118
 
97
119
  ### Updating State
98
120
 
99
- Updating state is done with methods like `.update()`, `.insert()`, and `.cut()`.
100
-
101
121
  ```typescript
102
- // Direct update
103
- settings.darkMode.update(true);
122
+ const user = useCogsState('user');
123
+ const settings = useCogsState('settings');
124
+ const todos = useCogsState('todos');
125
+
126
+ // Direct updates
127
+ user.name.update('Jane');
128
+ settings.darkMode.toggle();
104
129
 
105
- // Functional update (based on previous value)
106
- cart.total.update((prevTotal) => prevTotal + 10);
130
+ // Functional updates
131
+ user.stats.counter.update((prev) => prev + 1);
107
132
 
108
- // Deep update on an object within an array
109
- cart.items.findWith("id", "123").name.update("New Product Name");
133
+ // Object updates
134
+ user.update((prev) => ({ ...prev, name: 'Jane', age: 30 }));
135
+
136
+ // Deep nested updates
137
+ todos.index(0).text.update('Updated todo text');
110
138
  ```
111
139
 
112
140
  ## Working with Arrays
113
141
 
114
- Cogsbox provides powerful, chainable methods for array manipulation.
142
+ Arrays are first-class citizens with powerful built-in operations:
115
143
 
116
144
  ### Basic Array Operations
117
145
 
118
146
  ```typescript
119
- const cart = useCogsState("cart");
120
-
121
- // Add an item to the end of the array
122
- cart.items.insert({
123
- id: "prod1",
124
- name: "Product 1",
125
- price: 29.99,
126
- quantity: 1,
127
- });
147
+ const todos = useCogsState('todos');
148
+
149
+ // Add items
150
+ todos.insert({ id: 'uuid', text: 'New todo', done: false });
151
+ todos.insert(({ uuid }) => ({
152
+ id: uuid,
153
+ text: 'Auto-generated ID',
154
+ done: false,
155
+ }));
156
+
157
+ // Remove items
158
+ todos.cut(2); // Remove at index 2
159
+ todos.cutSelected(); // Remove currently selected item
160
+
161
+ // Access items
162
+ const firstTodo = todos.index(0);
163
+ const lastTodo = todos.last();
164
+ ```
128
165
 
129
- // Remove the item at index 2
130
- cart.items.cut(2);
166
+ ### Array Iteration and Rendering
131
167
 
132
- // Update an item at a specific index
133
- cart.items.index(0).price.update(19.99);
168
+ #### `stateMap()` - Enhanced Array Mapping
169
+
170
+ ```typescript
171
+ const todos = useCogsState('todos');
172
+
173
+ // Returns transformed array, each item is a full state object
174
+ const todoElements = todos.stateMap((todoState, index, arrayState) => (
175
+ <TodoItem
176
+ key={todoState.id.get()}
177
+ todo={todoState}
178
+ onToggle={() => todoState.done.toggle()}
179
+ onDelete={() => arrayState.cut(index)}
180
+ />
181
+ ));
134
182
  ```
135
183
 
136
- ### Finding and Updating Items
184
+ #### `stateList()` - JSX List Rendering
137
185
 
138
186
  ```typescript
139
- // Find an item by a property's value and update it
140
- cart.items.findWith("id", "prod1").quantity.update((q) => q + 1);
141
-
142
- // Find an item using a callback function (like array.find)
143
- const firstInStock = cart.items.stateFind((item) => item.stock > 0);
144
- if (firstInStock) {
145
- // `firstInStock` is a state object, so you can chain updates
146
- firstInStock.name.update((name) => `${name} (First Available!)`);
187
+ const todos = useCogsState('todos');
188
+
189
+ // Renders directly in place with automatic key management
190
+ {todos.stateList((todoState, index, arrayState) => (
191
+ <div key={todoState.id.get()}>
192
+ <span>{todoState.text.get()}</span>
193
+ <button onClick={() => todoState.done.toggle()}>Toggle</button>
194
+ <button onClick={() => arrayState.cut(index)}>Delete</button>
195
+ </div>
196
+ ))}
197
+ ```
198
+
199
+ #### `$stateMap()` - Signal-Based Rendering
200
+
201
+ ```typescript
202
+ const todos = useCogsState('todos');
203
+
204
+ // Most efficient - updates only changed items, no React re-renders
205
+ {todos.$stateMap((todoState, index, arrayState) => (
206
+ <TodoItem todo={todoState} />
207
+ ))}
208
+ ```
209
+
210
+ ### Advanced Array Methods
211
+
212
+ #### Filtering and Sorting
213
+
214
+ ```typescript
215
+ const todos = useCogsState('todos');
216
+
217
+ // Filter items (returns new state object with filtered view)
218
+ const completedTodos = todos.stateFilter((todo) => todo.done);
219
+ const incompleteTodos = todos.stateFilter((todo) => !todo.done);
220
+
221
+ // Sort items (returns new state object with sorted view)
222
+ const sortedTodos = todos.stateSort((a, b) => a.text.localeCompare(b.text));
223
+
224
+ // Chain operations
225
+ const sortedCompletedTodos = todos
226
+ .stateFilter((todo) => todo.done)
227
+ .stateSort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
228
+ ```
229
+
230
+ #### Finding and Searching
231
+
232
+ ```typescript
233
+ const todos = useCogsState('todos');
234
+
235
+ // Find by property value
236
+ const todoById = todos.findWith('id', 'some-id');
237
+ if (todoById) {
238
+ todoById.text.update('Updated text');
147
239
  }
240
+
241
+ // Find with custom function
242
+ const firstIncompleteTodo = todos.stateFind((todo) => !todo.done);
148
243
  ```
149
244
 
150
- ### Handling Selection
245
+ #### Unique Operations
246
+
247
+ ```typescript
248
+ const todos = useCogsState('todos');
249
+
250
+ // Insert only if unique (prevents duplicates)
251
+ todos.uniqueInsert(
252
+ { id: 'new-id', text: 'New todo', done: false },
253
+ ['id'], // Fields to check for uniqueness
254
+ (existingItem) => {
255
+ // Optional: callback if match found
256
+ return { ...existingItem, text: 'Updated existing' };
257
+ }
258
+ );
259
+
260
+ // Toggle presence (insert if missing, remove if present)
261
+ todos.toggleByValue('some-id');
262
+ ```
151
263
 
152
- Cogsbox has built-in support for managing a "selected" item within an array, perfect for lists.
264
+ #### Selection Management
153
265
 
154
266
  ```typescript
155
- function ProductList() {
156
- const cart = useCogsState("cart");
157
-
158
- // Get the fully selected item's state object to use elsewhere
159
- const selectedProduct = cart.items.getSelected();
160
-
161
- return (
162
- <div>
163
- <h3>Products</h3>
164
- {cart.items.stateMap((item, itemUpdater) => (
165
- <div
166
- key={item.id}
167
- // Use `_selected` to apply styling
168
- className={itemUpdater.\_selected ? "product selected" : "product"}
169
- // Use `toggleSelected` to handle clicks
170
- onClick={() => itemUpdater.toggleSelected()} >
171
- {item.name}
172
- </div>
173
- ))}
267
+ const todos = useCogsState('todos');
268
+
269
+ // Built-in selection tracking
270
+ const selectedTodo = todos.getSelected();
271
+ const selectedIndex = todos.getSelectedIndex();
174
272
 
175
- {selectedProduct && (
176
- <div className="details">
177
- <h4>Selected Details:</h4>
178
- <p>Name: {selectedProduct.name.get()}</p>
179
- <button onClick={() => selectedProduct.quantity.update(q => q + 1)}>
180
- Add one more
181
- </button>
273
+ // Set selection on individual items
274
+ todos.index(0).setSelected(true);
275
+ todos.index(0).toggleSelected();
276
+
277
+ // Clear all selections
278
+ todos.clearSelected();
279
+
280
+ // Check if item is selected
281
+ const isSelected = todos.index(0).isSelected;
282
+ ```
283
+
284
+ ### Virtualization for Large Lists
285
+
286
+ For performance with large datasets:
287
+
288
+ ```typescript
289
+ function MessageList() {
290
+ const messages = useCogsState('messages', { reactiveType: 'none' });
291
+
292
+ const { virtualState, virtualizerProps, scrollToBottom } =
293
+ messages.useVirtualView({
294
+ itemHeight: 65, // Height per item
295
+ overscan: 10, // Items to render outside viewport
296
+ stickToBottom: true, // Auto-scroll to bottom
297
+ scrollStickTolerance: 75 // Distance tolerance for bottom detection
298
+ });
299
+
300
+ return (
301
+ <div {...virtualizerProps.outer} className="h-96 overflow-auto">
302
+ <div style={virtualizerProps.inner.style}>
303
+ <div style={virtualizerProps.list.style}>
304
+ {virtualState.stateList((messageState, index) => (
305
+ <MessageItem key={messageState.id.get()} message={messageState} />
306
+ ))}
182
307
  </div>
183
- )}
308
+ </div>
184
309
  </div>
185
-
186
- );
310
+ );
187
311
  }
188
312
  ```
189
313
 
190
- ### Advanced Array Methods
314
+ ### Streaming for Real-time Data
191
315
 
192
316
  ```typescript
193
- // Map over items with full access to each item's updater
194
- cart.items.stateMap((item, itemUpdater, index) => (
195
- <CartItem
196
- key={item.id}
197
- item={item}
198
- // Pass the updater down to the child component
199
- onQuantityChange={newQty => itemUpdater.quantity.update(newQty)}
200
- onRemove={() => cart.items.cut(index)}
201
- />
202
- ));
317
+ const messages = useCogsState('messages');
318
+
319
+ // Create a stream for efficient batch operations
320
+ const messageStream = messages.stream({
321
+ bufferSize: 100, // Buffer size before auto-flush
322
+ flushInterval: 100, // Auto-flush interval (ms)
323
+ bufferStrategy: 'sliding', // 'sliding' | 'dropping' | 'accumulate'
324
+ store: (buffer) => buffer, // Transform buffered items before insertion
325
+ onFlush: (buffer) => console.log('Flushed', buffer.length, 'items'),
326
+ });
203
327
 
204
- // Filter items while keeping them as state objects
205
- const inStockItems = cart.products.stateFilter(product => product.stock > 0);
328
+ // Write individual items
329
+ messageStream.write(newMessage);
206
330
 
207
- // Insert an item only if it's not already in the array
208
- cart.items.uniqueInsert(
209
- { id: "prod1", name: "Product 1", quantity: 1 },
210
- ["id"] // Fields to check for uniqueness
211
- );
331
+ // Write multiple items
332
+ messageStream.writeMany([msg1, msg2, msg3]);
333
+
334
+ // Manual flush
335
+ messageStream.flush();
212
336
 
213
- // Flatten an array of nested arrays by a property name
214
- const allProductVariants = cart.products.stateFlattenOn("variants");
337
+ // Pause/resume
338
+ messageStream.pause();
339
+ messageStream.resume();
340
+
341
+ // Close stream
342
+ messageStream.close();
215
343
  ```
216
344
 
217
345
  ## Reactivity Control
218
346
 
219
- Cogsbox offers different ways to control when components re-render for performance optimization.
347
+ Cogsbox offers different reactivity modes for performance optimization:
220
348
 
221
349
  ### Component Reactivity (Default)
222
350
 
223
- The component re-renders whenever any state value accessed within it (using `.get()`) changes.
224
-
225
351
  ```typescript
226
- // Default behavior - re-renders when cart.items or cart.total changes
227
- const cart = useCogsState("cart");
228
-
229
- return (
230
-
231
- <div>
232
- <div>Items: {cart.items.get().length}</div>
233
- <div>Total: {cart.total.get()}</div>
234
- </div>
235
- );
352
+ // Re-renders when any accessed state changes
353
+ const user = useCogsState('user');
354
+ // or explicitly:
355
+ const user = useCogsState('user', { reactiveType: 'component' });
236
356
  ```
237
357
 
238
358
  ### Dependency-Based Reactivity
239
359
 
240
- The component re-renders _only_ when the values returned by `reactiveDeps` change.
241
-
242
360
  ```typescript
243
- // Only re-renders when the items array or status string changes
244
- const cart = useCogsState("cart", {
245
- reactiveType: ["deps"],
246
- reactiveDeps: (state) => [state.items, state.status],
361
+ // Only re-renders when specified dependencies change
362
+ const user = useCogsState('user', {
363
+ reactiveType: 'deps',
364
+ reactiveDeps: (state) => [state.name, state.stats.counter],
247
365
  });
248
366
  ```
249
367
 
250
368
  ### Full Reactivity
251
369
 
252
- The component re-renders on _any_ change to the state slice, even for properties not accessed in the component. Use with caution.
253
-
254
370
  ```typescript
255
- // Re-renders on any change to the 'cart' state
256
- const cart = useCogsState("cart", {
257
- reactiveType: ["all"],
258
- });
371
+ // Re-renders on ANY change to the state slice
372
+ const user = useCogsState('user', { reactiveType: 'all' });
259
373
  ```
260
374
 
261
- ### Signal-Based Reactivity (`$get` and `$derive`)
375
+ ### No Reactivity
376
+
377
+ ```typescript
378
+ // Never re-renders (useful with signals)
379
+ const todos = useCogsState('todos', { reactiveType: 'none' });
380
+ ```
262
381
 
263
- This is the most efficient method. It bypasses React's rendering entirely and updates only the specific DOM text nodes that depend on a value.
382
+ ### Multiple Reactivity Types
264
383
 
265
384
  ```typescript
266
- // Most efficient - updates just the specific text in the DOM
267
- return (
385
+ // Combine multiple reactivity modes
386
+ const user = useCogsState('user', {
387
+ reactiveType: ['component', 'deps'],
388
+ reactiveDeps: (state) => [state.online],
389
+ });
390
+ ```
268
391
 
269
- <div>
270
- {/* $derive transforms the value before rendering */}
271
- <div>Items: {cart.items.$derive(items => items.length)}</div>
392
+ ## Signal-Based Updates
272
393
 
273
- {/* $get renders the value directly */}
274
- <div>Total: {cart.total.$get()}</div>
394
+ The most efficient rendering method - bypasses React entirely:
275
395
 
276
- </div>
277
- );
396
+ ```typescript
397
+ function PerformantComponent() {
398
+ const user = useCogsState('user', { reactiveType: 'none' });
399
+ const todos = useCogsState('todos', { reactiveType: 'none' });
400
+
401
+ return (
402
+ <div>
403
+ {/* These update DOM directly, no React re-renders */}
404
+ <div>Name: {user.name.$get()}</div>
405
+ <div>Counter: {user.stats.counter.$get()}</div>
406
+ <div>Todo Count: {todos.$derive(todos => todos.length)}</div>
407
+
408
+ {/* Signal-based list rendering */}
409
+ {todos.$stateMap((todo, index) => (
410
+ <div key={todo.id.$get()}>
411
+ <span>{todo.text.$get()}</span>
412
+ <button onClick={() => todo.done.toggle()}>Toggle</button>
413
+ </div>
414
+ ))}
415
+
416
+ {/* Wrap with formElement for isolated reactivity */}
417
+ {user.stats.counter.formElement((obj) => (
418
+ <button onClick={() => obj.update(prev => prev + 1)}>
419
+ Increment: {obj.get()}
420
+ </button>
421
+ ))}
422
+ </div>
423
+ );
424
+ }
278
425
  ```
279
426
 
280
- ## Simple Forms with `formElement`
427
+ ## Form Management
281
428
 
282
- Cogsbox shines at form handling. The `formElement` method combined with `inputProps` removes nearly all boilerplate.
429
+ Cogsbox excels at form handling with automatic debouncing and validation:
430
+
431
+ ### Basic Form Elements
283
432
 
284
433
  ```typescript
285
434
  import { z } from 'zod';
286
- import { createCogsState } from 'cogsbox-state';
287
435
 
288
- // Define a Zod schema for validation
436
+ // Define validation schema
289
437
  const userSchema = z.object({
290
- name: z.string().min(1, "Name is required"),
291
- email: z.string().email("A valid email is required"),
292
- age: z.number().min(18, "You must be at least 18")
438
+ name: z.string().min(1, "Name is required"),
439
+ email: z.string().email("Invalid email"),
440
+ age: z.number().min(18, "Must be 18+")
293
441
  });
294
442
 
295
- // Create state with validation and a custom error wrapper
296
- export const { useCogsState } = createCogsState({
297
- userForm: {
298
- initialState: {
299
- name: "",
300
- email: "",
301
- age: 18
302
- },
303
- validation: {
304
- key: "userValidation", // A unique key for this form's errors
305
- zodSchema: userSchema
306
- },
307
- // Optional: A custom component to wrap fields and display errors
308
- formElements: {
309
- validation: ({ children, active, message }) => (
310
- <div className="form-field">
311
- {children}
312
- {active && <p className="error-message">{message}</p>}
313
- </div>
314
- )
315
- }
316
- }
443
+ // Create state with validation
444
+ const { useCogsState } = createCogsState({
445
+ userForm: {
446
+ initialState: { name: "", email: "", age: 18 },
447
+ validation: {
448
+ key: "userValidation",
449
+ zodSchema: userSchema,
450
+ onBlur: true // Validate on blur
451
+ },
452
+ formElements: {
453
+ validation: ({ children, active, message }) => (
454
+ <div className="form-field">
455
+ {children}
456
+ {active && <span className="error">{message}</span>}
457
+ </div>
458
+ )
459
+ }
460
+ }
317
461
  });
318
462
 
319
463
  function UserForm() {
320
- const user = useCogsState("userForm");
321
-
322
- const handleSubmit = (e) => {
323
- e.preventDefault();
324
- // Run all validations
325
- if (user.validateZodSchema()) {
326
- console.log("Form is valid!", user.get());
327
- } else {
328
- console.log("Form has errors.");
329
- }
330
- };
464
+ const userForm = useCogsState('userForm');
331
465
 
332
- return (
333
- <form onSubmit={handleSubmit}>
334
- {user.name.formElement((params) => (
335
- <>
336
- <label>Name</label>
337
- {/_ That's it! Spread inputProps to connect the input. _/}
338
- <input type="text" {...params.inputProps} />
339
- </>
340
- ))}
466
+ return (
467
+ <form>
468
+ {/* Auto-debounced input with validation wrapper */}
469
+ {userForm.name.formElement(({ inputProps }) => (
470
+ <>
471
+ <label>Name</label>
472
+ <input {...inputProps} />
473
+ </>
474
+ ))}
341
475
 
342
- {user.email.formElement((params) => (
476
+ {/* Custom debounce time */}
477
+ {userForm.email.formElement(({ inputProps, get, update }) => (
343
478
  <>
344
479
  <label>Email</label>
345
- <input type="email" {...params.inputProps} />
480
+ <input {...inputProps} />
481
+ <small>Current: {get()}</small>
346
482
  </>
347
- ))}
483
+ ), { debounceTime: 500 })}
348
484
 
349
- {user.age.formElement((params) => (
485
+ {/* Custom form control */}
486
+ {userForm.age.formElement(({ get, update }) => (
350
487
  <>
351
488
  <label>Age</label>
352
- <input type="number" {...params.inputProps} />
489
+ <input
490
+ type="number"
491
+ value={get()}
492
+ onChange={e => update(parseInt(e.target.value))}
493
+ />
353
494
  </>
354
495
  ))}
355
496
 
356
- <button type="submit">Submit</button>
497
+ <button onClick={() => {
498
+ if (userForm.validateZodSchema()) {
499
+ console.log('Valid!', userForm.get());
500
+ }
501
+ }}>
502
+ Submit
503
+ </button>
357
504
  </form>
505
+ );
506
+ }
507
+ ```
358
508
 
359
- );
509
+ ## Advanced Features
510
+
511
+ ### Server Synchronization
512
+
513
+ ```typescript
514
+ const { useCogsState } = createCogsState({
515
+ userProfile: {
516
+ initialState: { name: "", email: "" },
517
+ sync: {
518
+ action: async (state) => {
519
+ const response = await fetch('/api/user', {
520
+ method: 'PUT',
521
+ body: JSON.stringify(state)
522
+ });
523
+ return response.ok
524
+ ? { success: true, data: await response.json() }
525
+ : { success: false, error: 'Failed to save' };
526
+ },
527
+ onSuccess: (data) => console.log('Saved!', data),
528
+ onError: (error) => console.error('Save failed:', error)
529
+ }
530
+ }
531
+ });
532
+
533
+ function UserProfile() {
534
+ const userProfile = useCogsState('userProfile');
535
+
536
+ return (
537
+ <div>
538
+ <div>Status: {userProfile.getStatus()}</div> {/* 'fresh' | 'dirty' | 'synced' | 'restored' */}
539
+ <input
540
+ value={userProfile.name.get()}
541
+ onChange={e => userProfile.name.update(e.target.value)}
542
+ />
543
+ <button onClick={() => userProfile.sync()}>Save to Server</button>
544
+ </div>
545
+ );
360
546
  }
361
547
  ```
548
+
549
+ ### Local Storage Integration
550
+
551
+ ```typescript
552
+ const { useCogsState } = createCogsState({
553
+ userPrefs: {
554
+ initialState: { theme: 'dark', language: 'en' },
555
+ localStorage: {
556
+ key: 'user-preferences',
557
+ onChange: (state) => console.log('Saved to localStorage:', state),
558
+ },
559
+ },
560
+ });
561
+
562
+ function PreferencesComponent() {
563
+ const userPrefs = useCogsState('userPrefs');
564
+
565
+ return (
566
+ <div>
567
+ <select
568
+ value={userPrefs.theme.get()}
569
+ onChange={e => userPrefs.theme.update(e.target.value)}
570
+ >
571
+ <option value="dark">Dark</option>
572
+ <option value="light">Light</option>
573
+ </select>
574
+ </div>
575
+ );
576
+ }
577
+ ```
578
+
579
+ ### State Status and History
580
+
581
+ ```typescript
582
+ const user = useCogsState('user');
583
+
584
+ // Check what changed from initial state
585
+ const differences = user.getDifferences();
586
+
587
+ // Get current status
588
+ const status = user.getStatus(); // 'fresh' | 'dirty' | 'synced' | 'restored'
589
+
590
+ // Revert to initial state
591
+ user.revertToInitialState();
592
+
593
+ // Update initial state (useful for findign diffs and server-synced data)
594
+ const newServerData = {
595
+ name: 'Jane Doe',
596
+ age: 31,
597
+ stats: { counter: 100, lastUpdated: new Date() },
598
+ };
599
+ user.updateInitialState(newServerData);
600
+ ```
601
+
602
+ ### Component Isolation
603
+
604
+ ```typescript
605
+ // Each component can have its own reactive settings
606
+ function ComponentA() {
607
+ const user = useCogsState('user', {
608
+ reactiveType: 'deps',
609
+ reactiveDeps: (state) => [state.name],
610
+ });
611
+ // Only re-renders when user.name changes
612
+ }
613
+
614
+ function ComponentB() {
615
+ const user = useCogsState('user', {
616
+ reactiveType: 'all',
617
+ });
618
+ // Re-renders on any change to 'user' state
619
+ }
620
+ ```
621
+
622
+ ## Performance Tips
623
+
624
+ 1. **Use signals for high-frequency updates**: `.$get()` and `.$derive()` don't trigger React re-renders
625
+ 2. **Use `reactiveType: 'none'` with signals**: Maximum performance for signal-heavy components
626
+ 3. **Use virtualization for large lists**: `useVirtualView()` handles thousands of items efficiently
627
+ 4. **Use streaming for real-time data**: Batch operations with `stream()` for better performance
628
+ 5. **Chain filter/sort operations**: `stateFilter().stateSort()` creates efficient views
629
+ 6. **Use `formElement` for forms**: Automatic debouncing and validation handling
630
+
631
+ ## Common Patterns
632
+
633
+ ### Master-Detail Interface
634
+
635
+ ```typescript
636
+ function TodoApp() {
637
+ const todos = useCogsState('todos');
638
+ const selectedTodo = todos.getSelected();
639
+
640
+ return (
641
+ <div className="flex">
642
+ <div className="list">
643
+ {todos.stateList((todo, index) => (
644
+ <div
645
+ key={todo.id.get()}
646
+ className={todo.isSelected ? 'selected' : ''}
647
+ onClick={() => todo.toggleSelected()}
648
+ >
649
+ {todo.text.get()}
650
+ </div>
651
+ ))}
652
+ </div>
653
+
654
+ <div className="detail">
655
+ {selectedTodo ? (
656
+ <TodoDetail todo={selectedTodo} />
657
+ ) : (
658
+ <p>Select a todo</p>
659
+ )}
660
+ </div>
661
+ </div>
662
+ );
663
+ }
664
+ ```
665
+
666
+ ### Real-time Chat with Virtualization
667
+
668
+ ```typescript
669
+ function ChatRoom() {
670
+ const messages = useCogsState('messages', { reactiveType: 'none' });
671
+
672
+ const { virtualState, virtualizerProps, scrollToBottom } =
673
+ messages.useVirtualView({
674
+ itemHeight: 65,
675
+ overscan: 10,
676
+ stickToBottom: true,
677
+ });
678
+
679
+ return (
680
+ <div {...virtualizerProps.outer} className="chat-container">
681
+ <div style={virtualizerProps.inner.style}>
682
+ <div style={virtualizerProps.list.style}>
683
+ {virtualState.stateList((message) => (
684
+ <MessageItem key={message.id.$get()} message={message} />
685
+ ))}
686
+ </div>
687
+ </div>
688
+ </div>
689
+ );
690
+ }
691
+ ```
692
+
693
+ ### Multiple State Slices in One Component
694
+
695
+ ```typescript
696
+ function Dashboard() {
697
+ const user = useCogsState('user');
698
+ const todos = useCogsState('todos');
699
+ const settings = useCogsState('settings');
700
+
701
+ return (
702
+ <div>
703
+ <header>
704
+ <h1>Welcome, {user.name.get()}</h1>
705
+ <button onClick={() => settings.darkMode.toggle()}>
706
+ Toggle Theme
707
+ </button>
708
+ </header>
709
+
710
+ <main>
711
+ <p>You have {todos.get().length} todos</p>
712
+ <p>Counter: {user.stats.counter.get()}</p>
713
+ </main>
714
+ </div>
715
+ );
716
+ }
717
+ ```
718
+
719
+ This library provides a unique approach to React state management by creating a proxy that mirrors your data structure while adding powerful methods for manipulation, rendering, and performance optimization.