@veams/status-quo 1.7.0 → 1.8.0

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 (94) hide show
  1. package/.turbo/turbo-test.log +115 -15
  2. package/CHANGELOG.md +2 -0
  3. package/README.md +51 -7
  4. package/dist/config/status-quo-config.d.ts +22 -1
  5. package/dist/config/status-quo-config.js +46 -2
  6. package/dist/config/status-quo-config.js.map +1 -1
  7. package/dist/index.d.ts +12 -2
  8. package/dist/index.js +22 -2
  9. package/dist/index.js.map +1 -1
  10. package/dist/react/hooks/__tests__/state-provider.spec.js +2 -2
  11. package/dist/react/hooks/__tests__/state-provider.spec.js.map +1 -1
  12. package/dist/react/hooks/index.d.ts +6 -3
  13. package/dist/react/hooks/index.js +12 -3
  14. package/dist/react/hooks/index.js.map +1 -1
  15. package/dist/react/hooks/state-actions.d.ts +9 -1
  16. package/dist/react/hooks/state-actions.js +21 -2
  17. package/dist/react/hooks/state-actions.js.map +1 -1
  18. package/dist/react/hooks/state-factory.d.ts +7 -0
  19. package/dist/react/hooks/state-factory.js +23 -1
  20. package/dist/react/hooks/state-factory.js.map +1 -1
  21. package/dist/react/hooks/state-handler.d.ts +4 -0
  22. package/dist/react/hooks/state-handler.js +18 -1
  23. package/dist/react/hooks/state-handler.js.map +1 -1
  24. package/dist/react/hooks/state-provider.d.ts +18 -9
  25. package/dist/react/hooks/state-provider.js +25 -17
  26. package/dist/react/hooks/state-provider.js.map +1 -1
  27. package/dist/react/hooks/state-singleton.d.ts +8 -2
  28. package/dist/react/hooks/state-singleton.js +21 -3
  29. package/dist/react/hooks/state-singleton.js.map +1 -1
  30. package/dist/react/hooks/state-subscription-selector.d.ts +4 -0
  31. package/dist/react/hooks/state-subscription-selector.js +64 -8
  32. package/dist/react/hooks/state-subscription-selector.js.map +1 -1
  33. package/dist/react/hooks/state-subscription.d.ts +12 -0
  34. package/dist/react/hooks/state-subscription.js +49 -1
  35. package/dist/react/hooks/state-subscription.js.map +1 -1
  36. package/dist/react/index.d.ts +4 -1
  37. package/dist/react/index.js +5 -1
  38. package/dist/react/index.js.map +1 -1
  39. package/dist/store/__tests__/native-state-handler.spec.d.ts +1 -0
  40. package/dist/store/__tests__/native-state-handler.spec.js +210 -0
  41. package/dist/store/__tests__/native-state-handler.spec.js.map +1 -0
  42. package/dist/store/__tests__/observable-state-handler.spec.d.ts +7 -0
  43. package/dist/store/__tests__/observable-state-handler.spec.js.map +1 -1
  44. package/dist/store/base-state-handler.d.ts +42 -0
  45. package/dist/store/base-state-handler.js +73 -10
  46. package/dist/store/base-state-handler.js.map +1 -1
  47. package/dist/store/dev-tools.d.ts +42 -17
  48. package/dist/store/dev-tools.js +24 -8
  49. package/dist/store/dev-tools.js.map +1 -1
  50. package/dist/store/index.d.ts +7 -0
  51. package/dist/store/index.js +9 -0
  52. package/dist/store/index.js.map +1 -1
  53. package/dist/store/native-state-handler.d.ts +44 -0
  54. package/dist/store/native-state-handler.js +62 -0
  55. package/dist/store/native-state-handler.js.map +1 -0
  56. package/dist/store/observable-state-handler.d.ts +34 -0
  57. package/dist/store/observable-state-handler.js +45 -1
  58. package/dist/store/observable-state-handler.js.map +1 -1
  59. package/dist/store/signal-state-handler.d.ts +26 -0
  60. package/dist/store/signal-state-handler.js +35 -0
  61. package/dist/store/signal-state-handler.js.map +1 -1
  62. package/dist/store/state-singleton.d.ts +14 -0
  63. package/dist/store/state-singleton.js +20 -1
  64. package/dist/store/state-singleton.js.map +1 -1
  65. package/dist/types/types.d.ts +9 -0
  66. package/dist/types/types.js +3 -0
  67. package/dist/types/types.js.map +1 -1
  68. package/dist/utils/selector-cache.d.ts +17 -0
  69. package/dist/utils/selector-cache.js +28 -1
  70. package/dist/utils/selector-cache.js.map +1 -1
  71. package/package.json +12 -1
  72. package/src/config/status-quo-config.ts +64 -1
  73. package/src/index.ts +29 -0
  74. package/src/react/hooks/__tests__/state-provider.spec.tsx +2 -2
  75. package/src/react/hooks/index.ts +13 -8
  76. package/src/react/hooks/state-actions.tsx +23 -2
  77. package/src/react/hooks/state-factory.tsx +34 -0
  78. package/src/react/hooks/state-handler.tsx +15 -0
  79. package/src/react/hooks/state-provider.tsx +36 -40
  80. package/src/react/hooks/state-singleton.tsx +37 -7
  81. package/src/react/hooks/state-subscription-selector.tsx +85 -7
  82. package/src/react/hooks/state-subscription.tsx +75 -0
  83. package/src/react/index.ts +16 -1
  84. package/src/store/__tests__/native-state-handler.spec.ts +291 -0
  85. package/src/store/__tests__/observable-state-handler.spec.ts +8 -0
  86. package/src/store/base-state-handler.ts +89 -12
  87. package/src/store/dev-tools.ts +72 -27
  88. package/src/store/index.ts +16 -0
  89. package/src/store/native-state-handler.ts +98 -0
  90. package/src/store/observable-state-handler.ts +57 -0
  91. package/src/store/signal-state-handler.ts +47 -1
  92. package/src/store/state-singleton.ts +30 -0
  93. package/src/types/types.ts +16 -0
  94. package/src/utils/selector-cache.ts +37 -0
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Utility hook for subscribing to a state handler and selecting a specific value from the state.
3
+ * Uses useSyncExternalStore to ensure consistent state reads and avoid unnecessary re-renders.
4
+ */
1
5
  import { useCallback, useRef, useSyncExternalStore } from 'react';
2
6
 
3
7
  import { createSelectorCache, selectWithCache } from '../../utils/selector-cache.js';
@@ -5,33 +9,67 @@ import { createSelectorCache, selectWithCache } from '../../utils/selector-cache
5
9
  import type { StateSubscriptionHandler } from '../../types/types.js';
6
10
  import type { EqualityFn, Selector } from '../../utils/selector-cache.js';
7
11
 
12
+ /**
13
+ * Type signature for listener functions.
14
+ */
8
15
  type Listener = () => void;
16
+
17
+ /**
18
+ * Represents a state subscription handler with unknown state and actions.
19
+ */
9
20
  type SharedStateSubscriptionHandler = StateSubscriptionHandler<unknown, unknown>;
21
+
22
+ /**
23
+ * Tracks the reference count and deferred destruction status of a state handler.
24
+ */
10
25
  type DeferredDestroy = {
26
+ // Number of active consumers of the state handler.
11
27
  refCount: number;
28
+ // ID of the timeout for deferred destruction.
12
29
  timeoutId: ReturnType<typeof setTimeout> | null;
13
30
  };
31
+
32
+ /**
33
+ * Cache entry for a selected state snapshot.
34
+ */
14
35
  type SnapshotCacheEntry<Source, Selected> = {
36
+ // The selected value derived from the source snapshot.
15
37
  selectedSnapshot: Selected;
38
+ // The source snapshot from which the value was selected.
16
39
  sourceSnapshot: Source;
40
+ // A version number to track state changes.
17
41
  version: number;
18
42
  };
43
+
44
+ /**
45
+ * Cache entry for a selected server state snapshot (SSR).
46
+ */
19
47
  type ServerSnapshotCacheEntry<Source, Selected> = {
48
+ // The selected value derived from the source snapshot.
20
49
  selectedSnapshot: Selected;
50
+ // The source snapshot from which the value was selected.
21
51
  sourceSnapshot: Source;
22
52
  };
23
53
 
54
+ // Global map to track deferred destruction status for each state handler instance.
24
55
  const deferredDestroyMap = new WeakMap<SharedStateSubscriptionHandler, DeferredDestroy>();
25
56
 
57
+ /**
58
+ * Returns the deferred destruction status for a given state handler instance.
59
+ * Initializes the status if it does not already exist.
60
+ */
26
61
  function getDeferredDestroyState(
27
62
  stateSubscriptionHandler: SharedStateSubscriptionHandler
28
63
  ): DeferredDestroy {
64
+ // Retrieve the existing status from the map.
29
65
  const existingState = deferredDestroyMap.get(stateSubscriptionHandler);
30
66
 
67
+ // If status already exists, return it.
31
68
  if (existingState) {
32
69
  return existingState;
33
70
  }
34
71
 
72
+ // Create and store a new status for the handler.
35
73
  const nextState: DeferredDestroy = {
36
74
  refCount: 0,
37
75
  timeoutId: null,
@@ -42,78 +80,105 @@ function getDeferredDestroyState(
42
80
  return nextState;
43
81
  }
44
82
 
83
+ /**
84
+ * Custom hook to select and subscribe to a specific piece of state from a handler.
85
+ * Efficiently manages subscriptions and selector results.
86
+ */
45
87
  export function useStateSubscriptionSelector<V, A, Sel>(
88
+ // The state handler instance to subscribe to.
46
89
  stateSubscriptionHandler: StateSubscriptionHandler<V, A>,
90
+ // Selector function to derive a value from the state.
47
91
  selector: Selector<V, Sel>,
92
+ // Equality function to compare selected values for changes.
48
93
  isEqual: EqualityFn<Sel> = Object.is,
94
+ // Whether to automatically destroy the handler instance on component unmount.
49
95
  destroyOnCleanup = true
50
96
  ) {
97
+ // Cache for the selector results to ensure referential stability.
51
98
  const selectorCacheRef = useRef<ReturnType<typeof createSelectorCache<Sel>> | null>(null);
52
- // Tracks store notifications so getSnapshot can reuse the same selected value
53
- // within one store version. This keeps useSyncExternalStore reads referentially stable.
99
+ // Tracks store notifications so getSnapshot can reuse the same selected value within one store version.
54
100
  const snapshotVersionRef = useRef(0);
55
101
  // Client-side cache for selected snapshots per source snapshot/version pair.
56
102
  const snapshotCacheRef = useRef<SnapshotCacheEntry<V, Sel> | null>(null);
57
103
  // Separate cache for the server snapshot function used by SSR/hydration paths.
58
104
  const serverSnapshotCacheRef = useRef<ServerSnapshotCacheEntry<V, Sel> | null>(null);
59
105
 
106
+ // Initialize the selector cache if it doesn't already exist.
60
107
  if (!selectorCacheRef.current) {
61
108
  selectorCacheRef.current = createSelectorCache<Sel>();
62
109
  }
63
110
 
64
111
  const selectorCache = selectorCacheRef.current;
65
112
 
113
+ // Subscription function to be used by useSyncExternalStore.
66
114
  const subscribe = useCallback(
67
115
  (listener: Listener) => {
116
+ // Access the deferred destruction status for this handler.
68
117
  const sharedStateSubscriptionHandler =
69
118
  stateSubscriptionHandler as unknown as SharedStateSubscriptionHandler;
70
119
  const deferredDestroyState = getDeferredDestroyState(sharedStateSubscriptionHandler);
120
+ // Increment the consumer reference count.
71
121
  deferredDestroyState.refCount += 1;
72
122
 
123
+ // If a pending destruction timeout is scheduled, cancel it.
73
124
  if (deferredDestroyState.timeoutId) {
74
125
  clearTimeout(deferredDestroyState.timeoutId);
75
126
  deferredDestroyState.timeoutId = null;
76
127
  }
77
128
 
129
+ // Subscribe to the state handler.
78
130
  const unsubscribe = stateSubscriptionHandler.subscribe(() => {
79
- // Invalidate the selected snapshot cache before notifying React.
80
- // Any next getSnapshot call should recompute from the new store state.
131
+ // Invalidate the selected snapshot cache before notifying React of a change.
81
132
  snapshotVersionRef.current += 1;
82
133
  snapshotCacheRef.current = null;
134
+ // Notify React to re-trigger a getSnapshot call.
83
135
  listener();
84
136
  });
85
137
 
138
+ // Return an unsubscribe function to be called by React.
86
139
  return () => {
140
+ // Execute the handler's unsubscribe method.
87
141
  unsubscribe();
88
142
 
143
+ // If automatic cleanup is disabled, stop here.
89
144
  if (!destroyOnCleanup) {
90
145
  return;
91
146
  }
92
147
 
148
+ // Retrieve the current destruction status.
93
149
  const activeDeferredDestroyState = deferredDestroyMap.get(sharedStateSubscriptionHandler);
94
150
 
151
+ // If no status is found, stop here.
95
152
  if (!activeDeferredDestroyState) {
96
153
  return;
97
154
  }
98
155
 
156
+ // Decrement the consumer reference count.
99
157
  activeDeferredDestroyState.refCount -= 1;
100
158
 
159
+ // If there are still active consumers, do not destroy the handler.
101
160
  if (activeDeferredDestroyState.refCount > 0) {
102
161
  return;
103
162
  }
104
163
 
164
+ // Reset the reference count to zero.
105
165
  activeDeferredDestroyState.refCount = 0;
166
+ // Schedule deferred destruction to allow for potential immediate re-subscriptions.
106
167
  activeDeferredDestroyState.timeoutId = setTimeout(() => {
168
+ // Check if the handler still has no consumers after the timeout.
107
169
  const pendingDeferredDestroyState = deferredDestroyMap.get(
108
170
  sharedStateSubscriptionHandler
109
171
  );
110
172
 
173
+ // If consumers have reappeared, do not destroy the handler.
111
174
  if (!pendingDeferredDestroyState || pendingDeferredDestroyState.refCount > 0) {
112
175
  return;
113
176
  }
114
177
 
178
+ // Clear the pending timeout and destroy the state handler.
115
179
  pendingDeferredDestroyState.timeoutId = null;
116
180
  stateSubscriptionHandler.destroy();
181
+ // Remove the status from the global map.
117
182
  deferredDestroyMap.delete(sharedStateSubscriptionHandler);
118
183
  }, 0);
119
184
  };
@@ -121,6 +186,7 @@ export function useStateSubscriptionSelector<V, A, Sel>(
121
186
  [destroyOnCleanup, stateSubscriptionHandler]
122
187
  );
123
188
 
189
+ // Helper to execute selection using the cache.
124
190
  const selectSnapshot = useCallback(
125
191
  (snapshot: V) => {
126
192
  return selectWithCache(selectorCache, snapshot, selector, isEqual).value;
@@ -128,31 +194,36 @@ export function useStateSubscriptionSelector<V, A, Sel>(
128
194
  [isEqual, selector, selectorCache]
129
195
  );
130
196
 
197
+ // Reference to track changes in selection strategy.
131
198
  const selectorCacheControlRef = useRef(selectSnapshot);
132
199
 
200
+ // If the selector or equality function changes, clear all caches.
133
201
  if (selectorCacheControlRef.current !== selectSnapshot) {
134
- // Selector/equality changes define a new selection strategy, so clear all caches.
135
202
  selectorCacheControlRef.current = selectSnapshot;
136
203
  snapshotVersionRef.current = 0;
137
204
  snapshotCacheRef.current = null;
138
205
  serverSnapshotCacheRef.current = null;
139
206
  }
140
207
 
208
+ // Snapshot retrieval function to be used by useSyncExternalStore.
141
209
  const getSnapshot = useCallback(
142
210
  () => {
211
+ // Retrieve the current source state from the handler.
143
212
  const sourceSnapshot = stateSubscriptionHandler.getSnapshot();
213
+ // Access the current version and cached value.
144
214
  const version = snapshotVersionRef.current;
145
215
  const cachedSnapshot = snapshotCacheRef.current;
146
216
 
217
+ // If the cached selection is still valid for this version and source state, return it.
147
218
  if (
148
219
  cachedSnapshot &&
149
220
  cachedSnapshot.version === version &&
150
221
  Object.is(cachedSnapshot.sourceSnapshot, sourceSnapshot)
151
222
  ) {
152
- // Same source snapshot in the same store version: return the exact same selected reference.
153
223
  return cachedSnapshot.selectedSnapshot;
154
224
  }
155
225
 
226
+ // Compute a new selection and update the cache.
156
227
  const selectedSnapshot = selectSnapshot(sourceSnapshot);
157
228
  snapshotCacheRef.current = {
158
229
  selectedSnapshot,
@@ -160,31 +231,38 @@ export function useStateSubscriptionSelector<V, A, Sel>(
160
231
  version,
161
232
  };
162
233
 
234
+ // Return the new selection.
163
235
  return selectedSnapshot;
164
236
  },
165
237
  [selectSnapshot, stateSubscriptionHandler]
166
238
  );
167
239
 
240
+ // Server snapshot retrieval function to be used for SSR/hydration.
168
241
  const getServerSnapshot = useCallback(
169
242
  () => {
243
+ // Retrieve the initial source state from the handler.
170
244
  const sourceSnapshot = stateSubscriptionHandler.getInitialState();
245
+ // Access the current cached server snapshot.
171
246
  const cachedSnapshot = serverSnapshotCacheRef.current;
172
247
 
248
+ // If the cached server selection is still valid for the initial state, return it.
173
249
  if (cachedSnapshot && Object.is(cachedSnapshot.sourceSnapshot, sourceSnapshot)) {
174
- // Keep server snapshot reads stable for hydration by reusing cached selection.
175
250
  return cachedSnapshot.selectedSnapshot;
176
251
  }
177
252
 
253
+ // Compute a new server selection and update its cache.
178
254
  const selectedSnapshot = selectSnapshot(sourceSnapshot);
179
255
  serverSnapshotCacheRef.current = {
180
256
  selectedSnapshot,
181
257
  sourceSnapshot,
182
258
  };
183
259
 
260
+ // Return the initial selection result.
184
261
  return selectedSnapshot;
185
262
  },
186
263
  [selectSnapshot, stateSubscriptionHandler]
187
264
  );
188
265
 
266
+ // Use the useSyncExternalStore hook to integrate the state with React's rendering lifecycle.
189
267
  return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
190
268
  }
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Utility hook for subscribing to a state handler or a state singleton.
3
+ * Manages the lifecycle and reference counting for shared state handler instances.
4
+ */
1
5
  import { useEffect, useMemo } from 'react';
2
6
 
3
7
  import { useStateActions } from './state-actions.js';
@@ -5,28 +9,57 @@ import { useStateSubscriptionSelector } from './state-subscription-selector.js';
5
9
 
6
10
  import type { StateSingleton } from '../../store/state-singleton.js';
7
11
  import type { StateSubscriptionHandler } from '../../types/types.js';
12
+ import { useProvidedStateHandler } from './state-provider.js';
8
13
 
14
+ /**
15
+ * Type signatures for selector and equality functions.
16
+ */
9
17
  type StateSelector<State, SelectedState> = (state: State) => SelectedState;
10
18
  type EqualityFn<SelectedState> = (current: SelectedState, next: SelectedState) => boolean;
19
+
20
+ /**
21
+ * Interface representing a state singleton with optional internal management methods.
22
+ */
11
23
  type ManagedSingleton = StateSingleton<unknown, unknown> & {
24
+ // Method to manually destroy the singleton instance.
12
25
  destroyInstance?: () => void;
26
+ // Flag indicating if the instance should be destroyed when no more consumers are active.
13
27
  destroyOnNoConsumers?: boolean;
14
28
  };
29
+
30
+ /**
31
+ * Alias for a standard state handler instance.
32
+ */
15
33
  type SharedStateHandler = StateSubscriptionHandler<unknown, unknown>;
16
34
 
35
+ /**
36
+ * Global map to track reference counts for singleton state handler instances.
37
+ * Used to determine when it's safe to destroy a shared singleton.
38
+ */
17
39
  const singletonReferences = new WeakMap<
18
40
  StateSingleton<unknown, unknown>,
19
41
  { count: number; stateHandler: SharedStateHandler }
20
42
  >();
21
43
 
44
+ /**
45
+ * Default identity selector returns the whole state.
46
+ */
22
47
  const identitySelector = <State,>(state: State) => state;
23
48
 
49
+ /**
50
+ * Type guard function to check if a source is a StateSingleton.
51
+ */
24
52
  function isStateSingleton<V, A>(
25
53
  source: StateSubscriptionHandler<V, A> | StateSingleton<V, A>
26
54
  ): source is StateSingleton<V, A> {
55
+ // Check for the presence of the getInstance method.
27
56
  return 'getInstance' in source;
28
57
  }
29
58
 
59
+ /**
60
+ * Custom hook to subscribe to a state handler or singleton and receive its state and actions.
61
+ * Correctly manages shared instances and reference counting.
62
+ */
30
63
  export function useStateSubscription<V, A>(source: StateSubscriptionHandler<V, A>): [V, A];
31
64
  export function useStateSubscription<V, A, Sel>(
32
65
  source: StateSubscriptionHandler<V, A>,
@@ -40,66 +73,108 @@ export function useStateSubscription<V, A, Sel>(
40
73
  isEqual?: EqualityFn<Sel>
41
74
  ): [Sel, A];
42
75
  export function useStateSubscription<V, A, Sel = V>(
76
+ // Implementation of the overloaded useStateSubscription hook.
43
77
  source: StateSubscriptionHandler<V, A> | StateSingleton<V, A>,
78
+ // Selector function to derive a specific value from the state.
44
79
  selector: StateSelector<V, Sel> = identitySelector as StateSelector<V, Sel>,
80
+ // Optional equality function to compare selected values for changes.
45
81
  isEqual: EqualityFn<Sel> = Object.is
46
82
  ) {
83
+ // Determine if the source is a singleton instance or a direct state handler.
47
84
  const singletonSource = isStateSingleton(source) ? source : null;
85
+ // Resolve the final state subscription handler instance to use.
48
86
  const stateSubscriptionHandler = useMemo<StateSubscriptionHandler<V, A>>(() => {
87
+ // If it's a singleton, access its managed instance.
49
88
  if (singletonSource) {
50
89
  return singletonSource.getInstance();
51
90
  }
52
91
 
92
+ // Otherwise, return the source handler instance directly.
53
93
  return source as StateSubscriptionHandler<V, A>;
54
94
  }, [singletonSource, source]);
55
95
 
96
+ // Use an effect to manage the lifecycle and reference count of singleton instances.
56
97
  useEffect(() => {
98
+ // If the source is not a singleton, no lifecycle management is needed here.
57
99
  if (!singletonSource) {
58
100
  return undefined;
59
101
  }
60
102
 
103
+ // Cast the source to access management properties and retrieve the current reference.
61
104
  const singleton = singletonSource as ManagedSingleton;
62
105
  const sharedStateHandler = stateSubscriptionHandler as SharedStateHandler;
63
106
  const singletonReference = singletonReferences.get(singleton);
64
107
 
108
+ // Update the reference count for the singleton instance.
65
109
  if (!singletonReference || singletonReference.stateHandler !== sharedStateHandler) {
110
+ // Initialize the count if it doesn't already exist or has changed.
66
111
  singletonReferences.set(singleton, { count: 1, stateHandler: sharedStateHandler });
67
112
  } else {
113
+ // Increment the consumer count.
68
114
  singletonReference.count += 1;
69
115
  }
70
116
 
117
+ // Return an effect cleanup function to decrement the count when the component unmounts.
71
118
  return () => {
119
+ // Access the active reference for the singleton.
72
120
  const activeReference = singletonReferences.get(singleton);
73
121
 
122
+ // If no active reference is found, do nothing.
74
123
  if (!activeReference || activeReference.stateHandler !== sharedStateHandler) {
75
124
  return;
76
125
  }
77
126
 
127
+ // Decrement the consumer count.
78
128
  activeReference.count -= 1;
79
129
 
130
+ // If there are still active consumers, do not destroy the instance.
80
131
  if (activeReference.count <= 0) {
132
+ // Remove the reference from the map when the count reaches zero.
81
133
  singletonReferences.delete(singleton);
134
+
135
+ // Only proceed with destruction if destroyOnNoConsumers is explicitly enabled.
82
136
  if (singleton.destroyOnNoConsumers !== true) {
83
137
  return;
84
138
  }
85
139
 
140
+ // Use the singleton's internal destroy method if available.
86
141
  if (singleton.destroyInstance) {
87
142
  singleton.destroyInstance();
88
143
  return;
89
144
  }
90
145
 
146
+ // Otherwise, invoke the handler's destroy method directly.
91
147
  stateSubscriptionHandler.destroy();
92
148
  }
93
149
  };
94
150
  }, [singletonSource, stateSubscriptionHandler]);
95
151
 
152
+ // Select and subscribe to the state value using the useStateSubscriptionSelector hook.
96
153
  const state = useStateSubscriptionSelector(
97
154
  stateSubscriptionHandler,
98
155
  selector,
99
156
  isEqual,
100
157
  !singletonSource
101
158
  );
159
+ // Retrieve the set of actions from the state handler.
102
160
  const actions = useStateActions(stateSubscriptionHandler);
103
161
 
162
+ // Return the selected state and its actions as a tuple.
104
163
  return [state, actions] as [Sel, A];
105
164
  }
165
+
166
+ /**
167
+ * Custom hook to subscribe to the state handler provided by the nearest StateProvider.
168
+ */
169
+ export function useProvidedStateSubscription<V, A>(): [V, A];
170
+ export function useProvidedStateSubscription<V, A, Sel>(
171
+ selector: StateSelector<V, Sel>,
172
+ isEqual?: EqualityFn<Sel>
173
+ ): [Sel, A];
174
+ export function useProvidedStateSubscription<V, A, Sel = V>(
175
+ selector: StateSelector<V, Sel> = identitySelector as StateSelector<V, Sel>,
176
+ isEqual: EqualityFn<Sel> = Object.is
177
+ ) {
178
+ const stateHandler = useProvidedStateHandler<V, A>();
179
+ return useStateSubscription(stateHandler, selector, isEqual);
180
+ }
@@ -1 +1,16 @@
1
- export * from './hooks/index.js';
1
+ /**
2
+ * Export core React hooks and components for Status Quo.
3
+ */
4
+
5
+ // Export hooks and components to manage state and actions.
6
+ export {
7
+ StateProvider,
8
+ useProvidedStateActions,
9
+ useProvidedStateHandler,
10
+ useProvidedStateSubscription,
11
+ useStateActions,
12
+ useStateFactory,
13
+ useStateHandler,
14
+ useStateSingleton,
15
+ useStateSubscription,
16
+ } from './hooks/index.js';