react-state-custom 1.0.11 → 1.0.12

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.
@@ -0,0 +1,883 @@
1
+ # React State Custom - API Documentation
2
+
3
+ A powerful React library for managing shared state and context with TypeScript support, built with Vite.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Core Context System](#core-context-system)
8
+ - [Context Class](#context-class)
9
+ - [getContext](#getcontext)
10
+ - [useDataContext](#usedatacontext)
11
+ 2. [Data Source Hooks](#data-source-hooks)
12
+ - [useDataSource](#usedatasource)
13
+ - [useDataSourceMultiple](#usedatasourcemultiple)
14
+ 3. [Data Subscription Hooks](#data-subscription-hooks)
15
+ - [useDataSubscribe](#usedatasubscribe)
16
+ - [useDataSubscribeMultiple](#usedatasubscribemultiple)
17
+ - [useDataSubscribeMultipleWithDebounce](#usedatasubscribemultiplewithbounce)
18
+ - [useDataSubscribeWithTransform](#usedatasubscribewithtransform)
19
+ 4. [Root Context Factory](#root-context-factory)
20
+ - [createRootCtx](#createrootctx)
21
+ 5. [Auto Context System](#auto-context-system)
22
+ - [AutoRootCtx](#autorootctx)
23
+ - [createAutoCtx](#createautoctx)
24
+ 6. [Utility Hooks](#utility-hooks)
25
+ - [useArrayHash](#usearrayhash)
26
+ - [useQuickSubscribe](#usequicksubscribe)
27
+ 7. [Usage Patterns](#usage-patterns)
28
+ 8. [Examples](#examples)
29
+
30
+ ---
31
+
32
+ ## Core Context System
33
+
34
+ ### Context Class
35
+
36
+ A generic context class for managing shared state and event subscriptions.
37
+
38
+ **Type Definition:**
39
+ ```typescript
40
+ class Context<D> {
41
+ constructor(name: string)
42
+ data: Partial<D>
43
+ registry: Set<string>
44
+ publish(key: keyof D, value: D[typeof key] | undefined): void
45
+ subscribe(key: keyof D, listener: (e: D[typeof key] | undefined) => void): () => void
46
+ }
47
+ ```
48
+
49
+ **Parameters:**
50
+ - `D` - The shape of the data managed by the context
51
+
52
+ **Properties:**
53
+ - `name` - The name of the context (for debugging)
54
+ - `data` - The current data held by the context
55
+ - `registry` - Registry for tracking active keys
56
+
57
+ **Methods:**
58
+ - `publish(key, value)` - Publish a value to the context and notify subscribers if it changed
59
+ - `subscribe(key, listener)` - Subscribe to changes for a specific key, returns unsubscribe function
60
+
61
+ **Example:**
62
+ ```typescript
63
+ interface UserData {
64
+ name: string;
65
+ age: number;
66
+ email: string;
67
+ }
68
+
69
+ const userContext = new Context<UserData>('user-context');
70
+
71
+ // Subscribe to changes
72
+ const unsubscribe = userContext.subscribe('name', (newName) => {
73
+ console.log('Name changed to:', newName);
74
+ });
75
+
76
+ // Publish data
77
+ userContext.publish('name', 'John Doe');
78
+ userContext.publish('age', 30);
79
+
80
+ // Cleanup
81
+ unsubscribe();
82
+ ```
83
+
84
+ ---
85
+
86
+ ### getContext
87
+
88
+ Get or create a memoized Context instance by name.
89
+
90
+ **Type Definition:**
91
+ ```typescript
92
+ function getContext(name: string): Context<any>
93
+ ```
94
+
95
+ **Parameters:**
96
+ - `name` - The context name
97
+
98
+ **Returns:**
99
+ - The Context instance (memoized by name)
100
+
101
+ **Example:**
102
+ ```typescript
103
+ const userCtx = getContext('user-context');
104
+ const settingsCtx = getContext('settings-context');
105
+
106
+ // Same name returns the same instance
107
+ const userCtx2 = getContext('user-context');
108
+ console.log(userCtx === userCtx2); // true
109
+ ```
110
+
111
+ ---
112
+
113
+ ### useDataContext
114
+
115
+ React hook to get a typed Context instance by name.
116
+
117
+ **Type Definition:**
118
+ ```typescript
119
+ function useDataContext<D>(name?: string): Context<D>
120
+ ```
121
+
122
+ **Parameters:**
123
+ - `name` - The context name (default: "noname")
124
+
125
+ **Returns:**
126
+ - The typed Context instance
127
+
128
+ **Example:**
129
+ ```typescript
130
+ interface AppState {
131
+ user: User;
132
+ theme: 'light' | 'dark';
133
+ isLoading: boolean;
134
+ }
135
+
136
+ function MyComponent() {
137
+ const ctx = useDataContext<AppState>('app-state');
138
+
139
+ // Now ctx is typed as Context<AppState>
140
+ return <div>Context ready</div>;
141
+ }
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Data Source Hooks
147
+
148
+ ### useDataSource
149
+
150
+ React hook to publish a value to the context when it changes.
151
+
152
+ **Type Definition:**
153
+ ```typescript
154
+ function useDataSource<D, K extends keyof D>(
155
+ ctx: Context<D> | undefined,
156
+ key: K,
157
+ value: D[K] | undefined
158
+ ): void
159
+ ```
160
+
161
+ **Parameters:**
162
+ - `ctx` - The context instance
163
+ - `key` - The key to update
164
+ - `value` - The new value
165
+
166
+ **Example:**
167
+ ```typescript
168
+ interface UserState {
169
+ profile: UserProfile;
170
+ preferences: UserPreferences;
171
+ }
172
+
173
+ function UserProvider({ userId }: { userId: string }) {
174
+ const ctx = useDataContext<UserState>('user-state');
175
+ const userProfile = useFetchUserProfile(userId);
176
+ const userPreferences = useFetchUserPreferences(userId);
177
+
178
+ // Automatically publish to context when values change
179
+ useDataSource(ctx, 'profile', userProfile);
180
+ useDataSource(ctx, 'preferences', userPreferences);
181
+
182
+ return <>{children}</>;
183
+ }
184
+ ```
185
+
186
+ ---
187
+
188
+ ### useDataSourceMultiple
189
+
190
+ React hook to publish multiple values to the context.
191
+
192
+ **Type Definition:**
193
+ ```typescript
194
+ function useDataSourceMultiple<D, T extends readonly (keyof D)[]>(
195
+ ctx: Context<D> | undefined,
196
+ ...entries: { -readonly [P in keyof T]: [T[P], D[T[P]]] }
197
+ ): void
198
+ ```
199
+
200
+ **Parameters:**
201
+ - `ctx` - The context instance
202
+ - `entries` - Array of [key, value] pairs to update
203
+
204
+ **Example:**
205
+ ```typescript
206
+ function AppProvider() {
207
+ const ctx = useDataContext<AppState>('app-state');
208
+ const user = useCurrentUser();
209
+ const theme = useTheme();
210
+ const isLoading = useLoadingState();
211
+
212
+ // Publish multiple values at once
213
+ useDataSourceMultiple(ctx,
214
+ ['user', user],
215
+ ['theme', theme],
216
+ ['isLoading', isLoading]
217
+ );
218
+
219
+ return <>{children}</>;
220
+ }
221
+ ```
222
+
223
+ ---
224
+
225
+ ## Data Subscription Hooks
226
+
227
+ ### useDataSubscribe
228
+
229
+ React hook to subscribe to a context value, with optional debounce.
230
+
231
+ **Type Definition:**
232
+ ```typescript
233
+ function useDataSubscribe<D, K extends keyof D>(
234
+ ctx: Context<D> | undefined,
235
+ key: K,
236
+ debounceTime?: number
237
+ ): D[K] | undefined
238
+ ```
239
+
240
+ **Parameters:**
241
+ - `ctx` - The context instance
242
+ - `key` - The key to subscribe to
243
+ - `debounceTime` - Debounce time in ms (default: 0)
244
+
245
+ **Returns:**
246
+ - The current value for the key
247
+
248
+ **Example:**
249
+ ```typescript
250
+ function UserProfile() {
251
+ const ctx = useDataContext<UserState>('user-state');
252
+
253
+ // Subscribe to user profile changes
254
+ const profile = useDataSubscribe(ctx, 'profile');
255
+
256
+ // Subscribe with debouncing for frequently changing data
257
+ const searchQuery = useDataSubscribe(ctx, 'searchQuery', 300);
258
+
259
+ if (!profile) return <div>Loading...</div>;
260
+
261
+ return (
262
+ <div>
263
+ <h1>{profile.name}</h1>
264
+ <p>{profile.email}</p>
265
+ </div>
266
+ );
267
+ }
268
+ ```
269
+
270
+ ---
271
+
272
+ ### useDataSubscribeMultiple
273
+
274
+ React hook to subscribe to multiple context values.
275
+
276
+ **Type Definition:**
277
+ ```typescript
278
+ function useDataSubscribeMultiple<D, K extends keyof D>(
279
+ ctx: Context<D> | undefined,
280
+ ...keys: K[]
281
+ ): Pick<D, K>
282
+ ```
283
+
284
+ **Parameters:**
285
+ - `ctx` - The context instance
286
+ - `keys` - Keys to subscribe to
287
+
288
+ **Returns:**
289
+ - An object with the current values for the keys
290
+
291
+ **Example:**
292
+ ```typescript
293
+ function Dashboard() {
294
+ const ctx = useDataContext<AppState>('app-state');
295
+
296
+ // Subscribe to multiple values
297
+ const { user, theme, isLoading } = useDataSubscribeMultiple(
298
+ ctx,
299
+ 'user',
300
+ 'theme',
301
+ 'isLoading'
302
+ );
303
+
304
+ return (
305
+ <div className={`dashboard ${theme}`}>
306
+ {isLoading && <Spinner />}
307
+ <h1>Welcome, {user?.name}</h1>
308
+ </div>
309
+ );
310
+ }
311
+ ```
312
+
313
+ ---
314
+
315
+ ### useDataSubscribeMultipleWithDebounce
316
+
317
+ React hook to subscribe to multiple context values with throttling.
318
+
319
+ **Type Definition:**
320
+ ```typescript
321
+ function useDataSubscribeMultipleWithDebounce<D, K extends (keyof D)[]>(
322
+ ctx: Context<D> | undefined,
323
+ debounceTime?: number,
324
+ ...keys: K
325
+ ): { [i in keyof K]: D[K[i]] | undefined }
326
+ ```
327
+
328
+ **Parameters:**
329
+ - `ctx` - The context instance
330
+ - `debounceTime` - Debounce time in ms (default: 50)
331
+ - `keys` - Keys to subscribe to
332
+
333
+ **Returns:**
334
+ - Array of current values for the keys
335
+
336
+ **Example:**
337
+ ```typescript
338
+ function SearchResults() {
339
+ const ctx = useDataContext<SearchState>('search-state');
340
+
341
+ // Subscribe with debouncing for performance
342
+ const [query, filters, sortBy] = useDataSubscribeMultipleWithDebounce(
343
+ ctx,
344
+ 200, // 200ms debounce
345
+ 'query',
346
+ 'filters',
347
+ 'sortBy'
348
+ );
349
+
350
+ const results = useSearchResults(query, filters, sortBy);
351
+
352
+ return <ResultsList results={results} />;
353
+ }
354
+ ```
355
+
356
+ ---
357
+
358
+ ### useDataSubscribeWithTransform
359
+
360
+ React hook to subscribe to a context value and transform it before returning.
361
+
362
+ **Type Definition:**
363
+ ```typescript
364
+ function useDataSubscribeWithTransform<D, K extends keyof D, E>(
365
+ ctx: Context<D> | undefined,
366
+ key: K,
367
+ transform: (e: D[K] | undefined) => E
368
+ ): E
369
+ ```
370
+
371
+ **Parameters:**
372
+ - `ctx` - The context instance
373
+ - `key` - The key to subscribe to
374
+ - `transform` - Function to transform the value
375
+
376
+ **Returns:**
377
+ - The transformed value
378
+
379
+ **Example:**
380
+ ```typescript
381
+ function UserStats() {
382
+ const ctx = useDataContext<UserState>('user-state');
383
+
384
+ // Transform user data to display stats
385
+ const userStats = useDataSubscribeWithTransform(
386
+ ctx,
387
+ 'profile',
388
+ (profile) => ({
389
+ totalPosts: profile?.posts?.length || 0,
390
+ joinedDate: profile?.createdAt ? new Date(profile.createdAt) : null,
391
+ isVerified: profile?.verified || false
392
+ })
393
+ );
394
+
395
+ return (
396
+ <div>
397
+ <p>Posts: {userStats.totalPosts}</p>
398
+ <p>Joined: {userStats.joinedDate?.toLocaleDateString()}</p>
399
+ {userStats.isVerified && <Badge>Verified</Badge>}
400
+ </div>
401
+ );
402
+ }
403
+ ```
404
+
405
+ ---
406
+
407
+ ## Root Context Factory
408
+
409
+ ### createRootCtx
410
+
411
+ Factory that creates a headless "Root" component and companion hooks for a context namespace.
412
+
413
+ **Type Definition:**
414
+ ```typescript
415
+ function createRootCtx<U extends object, V extends object>(
416
+ name: string,
417
+ useFn: (e: U) => V
418
+ ): {
419
+ Root: React.FC<U>;
420
+ useCtxState: (e: U) => Context<V>;
421
+ useCtxStateStrict: (e: U) => Context<V>;
422
+ resolveCtxName: (e: U) => string;
423
+ }
424
+ ```
425
+
426
+ **Parameters:**
427
+ - `name` - Base name for the context
428
+ - `useFn` - Hook function that computes state from props
429
+
430
+ **Returns:**
431
+ - `Root` - Component to mount for providing the context
432
+ - `useCtxState` - Lenient consumer hook
433
+ - `useCtxStateStrict` - Strict consumer hook (throws if Root not mounted)
434
+ - `resolveCtxName` - Function to resolve context name from props
435
+
436
+ **Example:**
437
+ ```typescript
438
+ // Define your state hook
439
+ function useUserState(props: { userId: string }) {
440
+ const [user, setUser] = useState(null);
441
+ const [loading, setLoading] = useState(true);
442
+
443
+ useEffect(() => {
444
+ fetchUser(props.userId).then(user => {
445
+ setUser(user);
446
+ setLoading(false);
447
+ });
448
+ }, [props.userId]);
449
+
450
+ return { user, loading };
451
+ }
452
+
453
+ // Create the root context
454
+ const { Root: UserRoot, useCtxState: useUserCtxState } = createRootCtx(
455
+ 'user-state',
456
+ useUserState
457
+ );
458
+
459
+ // Provider component
460
+ function UserProvider({ userId, children }: { userId: string; children: React.ReactNode }) {
461
+ return (
462
+ <>
463
+ <UserRoot userId={userId} />
464
+ {children}
465
+ </>
466
+ );
467
+ }
468
+
469
+ // Consumer component
470
+ function UserProfile({ userId }: { userId: string }) {
471
+ const ctx = useUserCtxState({ userId });
472
+ const { user, loading } = useDataSubscribeMultiple(ctx, 'user', 'loading');
473
+
474
+ if (loading) return <div>Loading...</div>;
475
+
476
+ return <div>Hello, {user?.name}</div>;
477
+ }
478
+ ```
479
+
480
+ ---
481
+
482
+ ## Auto Context System
483
+
484
+ ### AutoRootCtx
485
+
486
+ Component for automatic context management. Mount once at the app root to enable automatic Root instance management.
487
+
488
+ **Type Definition:**
489
+ ```typescript
490
+ function AutoRootCtx({ Wrapper }: {
491
+ Wrapper?: React.ComponentType<{ children: React.ReactNode }>
492
+ }): JSX.Element
493
+ ```
494
+
495
+ **Parameters:**
496
+ - `Wrapper` - Optional wrapper component (should act like ErrorBoundary)
497
+
498
+ **Example:**
499
+ ```typescript
500
+ // At your app root
501
+ function App() {
502
+ return (
503
+ <>
504
+ <AutoRootCtx Wrapper={ErrorBoundary}/>
505
+ <Router>
506
+ <Routes>
507
+ <Route path="/user/:id" element={<UserPage />} />
508
+ </Routes>
509
+ </Router>
510
+ </>
511
+ );
512
+ }
513
+
514
+ // ErrorBoundary wrapper
515
+ function ErrorBoundary({ children }: { children: React.ReactNode }) {
516
+ // Your error boundary logic
517
+ return <>{children}</>;
518
+ }
519
+ ```
520
+
521
+ ---
522
+
523
+ ### createAutoCtx
524
+
525
+ Bridges a Root context (from createRootCtx) to the global AutoRootCtx renderer.
526
+
527
+ **Type Definition:**
528
+ ```typescript
529
+ function createAutoCtx<U extends object, V extends object>(
530
+ rootContext: ReturnType<typeof createRootCtx<U, V>>
531
+ ): {
532
+ useCtxState: (e: U) => Context<V>;
533
+ }
534
+ ```
535
+
536
+ **Parameters:**
537
+ - `rootContext` - Return value from createRootCtx
538
+
539
+ **Returns:**
540
+ - `useCtxState` - Hook that automatically manages Root instances
541
+
542
+ **Example:**
543
+ ```typescript
544
+ // Create auto context from root context
545
+ const { useCtxState: useUserCtxStateAuto } = createAutoCtx(
546
+ createRootCtx('user-state', useUserState)
547
+ );
548
+
549
+ // Usage - no need to manually mount Root components
550
+ function UserProfile({ userId }: { userId: string }) {
551
+ // This automatically manages the Root instance
552
+ const ctx = useUserCtxStateAuto({ userId });
553
+ const { user, loading } = useDataSubscribeMultiple(ctx, 'user', 'loading');
554
+
555
+ if (loading) return <div>Loading...</div>;
556
+
557
+ return <div>Hello, {user?.name}</div>;
558
+ }
559
+ ```
560
+
561
+ ---
562
+
563
+ ## Utility Hooks
564
+
565
+ ### useArrayHash
566
+
567
+ A custom hook that computes a stable hash for an array of values.
568
+
569
+ **Type Definition:**
570
+ ```typescript
571
+ function useArrayHash(e: any[]): string
572
+ ```
573
+
574
+ **Parameters:**
575
+ - `e` - The input array to hash
576
+
577
+ **Returns:**
578
+ - A string hash that updates when the array changes
579
+
580
+ **Example:**
581
+ ```typescript
582
+ function OptimizedComponent({ items }: { items: any[] }) {
583
+ // Get stable hash for the array
584
+ const itemsHash = useArrayHash(items);
585
+
586
+ // Only recalculate when hash changes
587
+ const processedItems = useMemo(() => {
588
+ return items.map(item => expensiveProcessing(item));
589
+ }, [itemsHash]);
590
+
591
+ return <div>{processedItems.length} items processed</div>;
592
+ }
593
+ ```
594
+
595
+ ---
596
+
597
+ ### useQuickSubscribe
598
+
599
+ Hook for efficiently subscribing to specific properties of a context's data object.
600
+
601
+ **Type Definition:**
602
+ ```typescript
603
+ function useQuickSubscribe<D>(
604
+ ctx: Context<D> | undefined
605
+ ): { [P in keyof D]?: D[P] | undefined }
606
+ ```
607
+
608
+ **Parameters:**
609
+ - `ctx` - The context object containing data and a subscribe method
610
+
611
+ **Returns:**
612
+ - A proxy object that mirrors the context data, automatically subscribing to accessed properties
613
+
614
+ **Example:**
615
+ ```typescript
616
+ function UserComponent() {
617
+ const ctx = useDataContext<UserState>('user-state');
618
+
619
+ // Only subscribes to properties you actually access
620
+ const { name, email } = useQuickSubscribe(ctx);
621
+ // Accessing 'name' and 'email' will subscribe to changes in those properties only
622
+
623
+ return (
624
+ <div>
625
+ <h1>{name}</h1>
626
+ <p>{email}</p>
627
+ {/* If you later access 'age', it will automatically subscribe to that too */}
628
+ </div>
629
+ );
630
+ }
631
+ ```
632
+
633
+ ---
634
+
635
+ ## Usage Patterns
636
+
637
+ ### Basic Context Usage
638
+
639
+ ```typescript
640
+ // 1. Define your data interface
641
+ interface AppState {
642
+ user: User | null;
643
+ theme: 'light' | 'dark';
644
+ notifications: Notification[];
645
+ }
646
+
647
+ // 2. Create and use context
648
+ function App() {
649
+ const ctx = useDataContext<AppState>('app-state');
650
+
651
+ // 3. Provide data
652
+ const user = useCurrentUser();
653
+ const theme = useTheme();
654
+ useDataSource(ctx, 'user', user);
655
+ useDataSource(ctx, 'theme', theme);
656
+
657
+ return <AppContent />;
658
+ }
659
+
660
+ // 4. Consume data
661
+ function AppContent() {
662
+ const ctx = useDataContext<AppState>('app-state');
663
+ const { user, theme } = useDataSubscribeMultiple(ctx, 'user', 'theme');
664
+
665
+ return <div className={`app ${theme}`}>Welcome, {user?.name}</div>;
666
+ }
667
+ ```
668
+
669
+ ### Advanced Root Context Pattern
670
+
671
+ ```typescript
672
+ // 1. Create state hook
673
+ function useAppState(props: { initialTheme: string }) {
674
+ const [theme, setTheme] = useState(props.initialTheme);
675
+ const [user, setUser] = useState(null);
676
+
677
+ return { theme, user, setTheme, setUser };
678
+ }
679
+
680
+ // 2. Create root context
681
+ const { Root: AppRoot, useCtxState } = createRootCtx('app', useAppState);
682
+
683
+ // 3. Provider pattern
684
+ function AppProvider({ children }: { children: React.ReactNode }) {
685
+ return (
686
+ <>
687
+ <AppRoot initialTheme="light" />
688
+ {children}
689
+ </>
690
+ );
691
+ }
692
+
693
+ // 4. Consumer hook
694
+ function useAppContext() {
695
+ return useCtxState({ initialTheme: 'light' });
696
+ }
697
+ ```
698
+
699
+ ### Auto Context Pattern
700
+
701
+ ```typescript
702
+ // 1. Setup auto context once
703
+ const { useCtxState: useAppState } = createAutoCtx(
704
+ createRootCtx('app-auto', useAppStateLogic)
705
+ );
706
+
707
+ // 2. Mount AutoRootCtx at app root
708
+ function App() {
709
+ return (
710
+ <AutoRootCtx Wrapper={ErrorBoundary}>
711
+ <MyApp />
712
+ </AutoRootCtx>
713
+ );
714
+ }
715
+
716
+ // 3. Use anywhere without manual Root mounting
717
+ function AnyComponent() {
718
+ const ctx = useAppState({ config: 'production' });
719
+ const data = useQuickSubscribe(ctx);
720
+
721
+ return <div>{data.someProperty}</div>;
722
+ }
723
+ ```
724
+
725
+ ---
726
+
727
+ ## Examples
728
+
729
+ ### Complete Todo App Example
730
+
731
+ ```typescript
732
+ // Types
733
+ interface TodoState {
734
+ todos: Todo[];
735
+ filter: 'all' | 'active' | 'completed';
736
+ newTodoText: string;
737
+ }
738
+
739
+ interface Todo {
740
+ id: string;
741
+ text: string;
742
+ completed: boolean;
743
+ }
744
+
745
+ // State hook
746
+ function useTodoState() {
747
+ const [todos, setTodos] = useState<Todo[]>([]);
748
+ const [filter, setFilter] = useState<'all' | 'active' | 'completed'>('all');
749
+ const [newTodoText, setNewTodoText] = useState('');
750
+
751
+ const addTodo = useCallback((text: string) => {
752
+ const newTodo: Todo = {
753
+ id: Date.now().toString(),
754
+ text,
755
+ completed: false
756
+ };
757
+ setTodos(prev => [...prev, newTodo]);
758
+ setNewTodoText('');
759
+ }, []);
760
+
761
+ const toggleTodo = useCallback((id: string) => {
762
+ setTodos(prev => prev.map(todo =>
763
+ todo.id === id ? { ...todo, completed: !todo.completed } : todo
764
+ ));
765
+ }, []);
766
+
767
+ return {
768
+ todos,
769
+ filter,
770
+ newTodoText,
771
+ setFilter,
772
+ setNewTodoText,
773
+ addTodo,
774
+ toggleTodo
775
+ };
776
+ }
777
+
778
+ // Auto context setup
779
+ const { useCtxState: useTodoContext } = createAutoCtx(
780
+ createRootCtx('todo-app', useTodoState)
781
+ );
782
+
783
+ // App component
784
+ function TodoApp() {
785
+ return (
786
+ <AutoRootCtx>
787
+ <div className="todo-app">
788
+ <TodoInput />
789
+ <TodoList />
790
+ <TodoFilters />
791
+ </div>
792
+ </AutoRootCtx>
793
+ );
794
+ }
795
+
796
+ // Input component
797
+ function TodoInput() {
798
+ const ctx = useTodoContext();
799
+ const { newTodoText, addTodo, setNewTodoText } = useQuickSubscribe(ctx);
800
+
801
+ const handleSubmit = (e: React.FormEvent) => {
802
+ e.preventDefault();
803
+ if (newTodoText.trim()) {
804
+ addTodo(newTodoText.trim());
805
+ }
806
+ };
807
+
808
+ return (
809
+ <form onSubmit={handleSubmit}>
810
+ <input
811
+ value={newTodoText}
812
+ onChange={(e) => setNewTodoText(e.target.value)}
813
+ placeholder="Add a new todo..."
814
+ />
815
+ <button type="submit">Add</button>
816
+ </form>
817
+ );
818
+ }
819
+
820
+ // List component
821
+ function TodoList() {
822
+ const ctx = useTodoContext();
823
+ const { todos, filter } = useDataSubscribeMultiple(ctx, 'todos', 'filter');
824
+
825
+ const filteredTodos = useMemo(() => {
826
+ switch (filter) {
827
+ case 'active':
828
+ return todos.filter(todo => !todo.completed);
829
+ case 'completed':
830
+ return todos.filter(todo => todo.completed);
831
+ default:
832
+ return todos;
833
+ }
834
+ }, [todos, filter]);
835
+
836
+ return (
837
+ <ul className="todo-list">
838
+ {filteredTodos.map(todo => (
839
+ <TodoItem key={todo.id} todo={todo} />
840
+ ))}
841
+ </ul>
842
+ );
843
+ }
844
+
845
+ // Todo item component
846
+ function TodoItem({ todo }: { todo: Todo }) {
847
+ const ctx = useTodoContext();
848
+ const { toggleTodo } = useQuickSubscribe(ctx);
849
+
850
+ return (
851
+ <li className={`todo-item ${todo.completed ? 'completed' : ''}`}>
852
+ <input
853
+ type="checkbox"
854
+ checked={todo.completed}
855
+ onChange={() => toggleTodo(todo.id)}
856
+ />
857
+ <span>{todo.text}</span>
858
+ </li>
859
+ );
860
+ }
861
+
862
+ // Filter component
863
+ function TodoFilters() {
864
+ const ctx = useTodoContext();
865
+ const { filter, setFilter } = useQuickSubscribe(ctx);
866
+
867
+ return (
868
+ <div className="todo-filters">
869
+ {(['all', 'active', 'completed'] as const).map(filterType => (
870
+ <button
871
+ key={filterType}
872
+ className={filter === filterType ? 'active' : ''}
873
+ onClick={() => setFilter(filterType)}
874
+ >
875
+ {filterType}
876
+ </button>
877
+ ))}
878
+ </div>
879
+ );
880
+ }
881
+ ```
882
+
883
+ This comprehensive documentation covers all exported APIs from the react-state-custom library with detailed descriptions, type information, and practical examples.
package/README.md CHANGED
@@ -1,57 +1,197 @@
1
- # My React Library
1
+ # React State Custom - Documentation
2
2
 
3
- This is a simple React library created using Yarn, Vite, and TypeScript. It includes a sample component that can be used in your React applications.
3
+ Welcome to the comprehensive documentation for the `react-state-custom` library!
4
4
 
5
- ## Installation
5
+ ## 📚 Documentation Files
6
6
 
7
- To install the library, you can use Yarn:
7
+ - **[API_DOCUMENTATION.md](./API_DOCUMENTATION.md)** - Complete API reference with examples for all exported functions, hooks, and classes
8
+
9
+ ## 🚀 Quick Start
8
10
 
9
11
  ```bash
10
- yarn add my-react-library
12
+ npm install react-state-custom
11
13
  ```
12
14
 
13
- ## Usage
14
-
15
- To use the `MyComponent` in your React application, you can import it as follows:
16
-
17
- ```tsx
18
- import { MyComponent } from 'my-react-library';
15
+ ## 📖 What's Inside
16
+
17
+ The `react-state-custom` library provides a powerful set of tools for managing shared state in React applications:
18
+
19
+ ### Core Features
20
+
21
+ - **Context System** - Type-safe context management with event-driven subscriptions
22
+ - **Root Context Factory** - Automated context lifecycle management
23
+ - **Auto Context System** - Self-managing context instances
24
+ - **Utility Hooks** - Performance optimization tools
25
+
26
+ ### Key Benefits
27
+
28
+ - ✅ **Type Safety** - Full TypeScript support with strong typing
29
+ - ✅ **Performance** - Only re-renders when subscribed data changes
30
+ - ✅ **Flexibility** - Works with any data structure
31
+ - ✅ **Developer Experience** - Rich debugging and error checking
32
+ - ✅ **Minimal Boilerplate** - Automated context management
33
+
34
+ ## 📝 Documentation Structure
35
+
36
+ The [API Documentation](./API_DOCUMENTATION.md) is organized into the following sections:
37
+
38
+ 1. **Core Context System** - Basic context functionality
39
+ 2. **Data Source Hooks** - Publishing data to contexts
40
+ 3. **Data Subscription Hooks** - Subscribing to context changes
41
+ 4. **Root Context Factory** - Advanced context patterns
42
+ 5. **Auto Context System** - Automated context management
43
+ 6. **Utility Hooks** - Performance and utility functions
44
+ 7. **Usage Patterns** - Common implementation patterns
45
+ 8. **Examples** - Complete application examples
46
+
47
+ ## 🎯 Common Use Cases
48
+
49
+ - **Global State Management** - Application-wide state without Redux complexity
50
+ - **Component Communication** - Share data between distant components
51
+ - **Performance Optimization** - Minimize unnecessary re-renders
52
+ - **Context Composition** - Combine multiple contexts efficiently
53
+
54
+ ## 🔧 Quick Example
55
+
56
+ ```typescript
57
+ import { useDataContext, useDataSource, useDataSubscribe } from 'react-state-custom';
58
+
59
+ interface AppState {
60
+ user: User | null;
61
+ theme: 'light' | 'dark';
62
+ }
63
+
64
+ // Provider component
65
+ function AppProvider({ children }) {
66
+ const ctx = useDataContext<AppState>('app-state');
67
+ const user = useCurrentUser();
68
+ const theme = useTheme();
69
+
70
+ useDataSource(ctx, 'user', user);
71
+ useDataSource(ctx, 'theme', theme);
72
+
73
+ return <>{children}</>;
74
+ }
75
+
76
+ // Consumer component
77
+ function UserProfile() {
78
+ const ctx = useDataContext<AppState>('app-state');
79
+ const user = useDataSubscribe(ctx, 'user');
80
+
81
+ return <div>Hello, {user?.name}</div>;
82
+ }
83
+ ```
19
84
 
20
- const App = () => {
85
+ ## 🔧 Additional Examples
86
+
87
+ ### Using createRootCtx for Advanced State Management
88
+
89
+ ```typescript
90
+ import { createRootCtx, useDataSubscribeMultiple } from 'react-state-custom';
91
+
92
+ interface UserState {
93
+ user: User | null;
94
+ loading: boolean;
95
+ error: string | null;
96
+ }
97
+
98
+ // Create a state hook
99
+ function useUserState(props: { userId: string }) {
100
+ const [user, setUser] = useState<User | null>(null);
101
+ const [loading, setLoading] = useState(true);
102
+ const [error, setError] = useState<string | null>(null);
103
+
104
+ useEffect(() => {
105
+ fetchUser(props.userId).then(setUser).catch(setError).finally(() => setLoading(false));
106
+ }, [props.userId]);
107
+
108
+ return { user, loading, error };
109
+ }
110
+
111
+ // Create root context factory
112
+ const { Root: UserRoot, useCtxState: useUserCtxState } = createRootCtx(
113
+ 'user-state',
114
+ useUserState
115
+ );
116
+
117
+ // Provider component
118
+ function UserProvider({ userId, children }: { userId: string; children: React.ReactNode }) {
21
119
  return (
22
- <div>
23
- <MyComponent propName="value" />
24
- </div>
120
+ <>
121
+ <UserRoot userId={userId} />
122
+ {children}
123
+ </>
25
124
  );
26
- };
27
-
28
- export default App;
125
+ }
126
+
127
+ // Consumer component using useDataSubscribeMultiple
128
+ function UserProfile({ userId }: { userId: string }) {
129
+ const ctx = useUserCtxState({ userId });
130
+ const { user, loading, error } = useDataSubscribeMultiple(ctx, 'user', 'loading', 'error');
131
+
132
+ if (loading) return <div>Loading user...</div>;
133
+ if (error) return <div>Error: {error}</div>;
134
+
135
+ return <div>Welcome, {user?.name}!</div>;
136
+ }
29
137
  ```
30
138
 
31
- ## Development
32
-
33
- To start developing the library, clone the repository and install the dependencies:
34
-
35
- ```bash
36
- git clone <repository-url>
37
- cd my-react-library
38
- yarn install
39
- ```
40
-
41
- To run the development server, use:
42
-
43
- ```bash
44
- yarn dev
139
+ ### Using useQuickSubscribe for Simplified Access
140
+
141
+ ```typescript
142
+ import { useDataContext, useQuickSubscribe } from 'react-state-custom';
143
+
144
+ interface SettingsState {
145
+ theme: 'light' | 'dark';
146
+ language: string;
147
+ notifications: boolean;
148
+ updateSetting: (key: string, value: any) => void;
149
+ }
150
+
151
+ // Component using useQuickSubscribe for easy property access
152
+ function SettingsPanel() {
153
+ const ctx = useDataContext<SettingsState>('settings');
154
+
155
+ // useQuickSubscribe automatically subscribes to accessed properties
156
+ const { theme, language, notifications, updateSetting } = useQuickSubscribe(ctx);
157
+
158
+ return (
159
+ <div className={`settings-panel ${theme}`}>
160
+ <h2>Settings</h2>
161
+
162
+ <label>
163
+ Theme:
164
+ <select value={theme} onChange={(e) => updateSetting('theme', e.target.value)}>
165
+ <option value="light">Light</option>
166
+ <option value="dark">Dark</option>
167
+ </select>
168
+ </label>
169
+
170
+ <label>
171
+ Language:
172
+ <input
173
+ value={language}
174
+ onChange={(e) => updateSetting('language', e.target.value)}
175
+ />
176
+ </label>
177
+
178
+ <label>
179
+ <input
180
+ type="checkbox"
181
+ checked={notifications}
182
+ onChange={(e) => updateSetting('notifications', e.target.checked)}
183
+ />
184
+ Enable notifications
185
+ </label>
186
+ </div>
187
+ );
188
+ }
45
189
  ```
46
190
 
47
- ## Building
48
-
49
- To build the library for production, run:
191
+ ## 📄 License
50
192
 
51
- ```bash
52
- yarn build
53
- ```
193
+ MIT License - see the main repository for details.
54
194
 
55
- ## License
195
+ ---
56
196
 
57
- This project is licensed under the MIT License. See the LICENSE file for more details.
197
+ For the complete API reference with detailed examples, see [API_DOCUMENTATION.md](./API_DOCUMENTATION.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-state-custom",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "A React library built with Vite and TypeScript",
5
5
  "type": "module",
6
6
  "main": "dist/index.umd.js",