@okyrychenko-dev/react-action-guard 0.7.0 → 1.0.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.
- package/README.md +21 -11
- package/dist/index.cjs +92 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +437 -402
- package/dist/index.d.ts +437 -402
- package/dist/index.js +87 -45
- package/dist/index.js.map +1 -1
- package/package.json +10 -9
package/dist/index.d.ts
CHANGED
|
@@ -1,161 +1,228 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
1
2
|
import * as zustand from 'zustand';
|
|
2
3
|
import { StoreApi } from 'zustand';
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
type AnalyticsEventData = Record<string, string | number | ReadonlyArray<string> | undefined>;
|
|
6
|
+
type AnalyticsProvider = "ga" | "mixpanel" | "amplitude";
|
|
7
|
+
interface GoogleAnalyticsConfig {
|
|
8
|
+
provider: "ga";
|
|
9
|
+
}
|
|
10
|
+
interface MixpanelConfig {
|
|
11
|
+
provider: "mixpanel";
|
|
12
|
+
}
|
|
13
|
+
interface AmplitudeConfig {
|
|
14
|
+
provider: "amplitude";
|
|
15
|
+
}
|
|
16
|
+
interface CustomAnalyticsConfig {
|
|
17
|
+
track: (event: string, data: AnalyticsEventData) => void;
|
|
18
|
+
}
|
|
19
|
+
type AnalyticsConfig = GoogleAnalyticsConfig | MixpanelConfig | AmplitudeConfig | CustomAnalyticsConfig;
|
|
5
20
|
|
|
6
21
|
/**
|
|
7
|
-
*
|
|
22
|
+
* Configuration options for creating or updating a blocker.
|
|
23
|
+
*
|
|
24
|
+
* All fields are optional. Defaults will be applied for any missing values:
|
|
25
|
+
* - `scope`: "global"
|
|
26
|
+
* - `reason`: "Blocking UI"
|
|
27
|
+
* - `priority`: 50
|
|
28
|
+
* - `timestamp`: Current time
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* Basic configuration
|
|
32
|
+
* ```ts
|
|
33
|
+
* const config: BlockerConfig = {
|
|
34
|
+
* scope: 'form',
|
|
35
|
+
* reason: 'Submitting data...',
|
|
36
|
+
* priority: 70
|
|
37
|
+
* };
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* With timeout and callback
|
|
42
|
+
* ```ts
|
|
43
|
+
* const config: BlockerConfig = {
|
|
44
|
+
* scope: ['form', 'navigation'],
|
|
45
|
+
* reason: 'Critical operation in progress',
|
|
46
|
+
* priority: 90,
|
|
47
|
+
* timeout: 30000, // 30 seconds
|
|
48
|
+
* onTimeout: (id) => {
|
|
49
|
+
* console.warn(`Blocker ${id} timed out`);
|
|
50
|
+
* }
|
|
51
|
+
* };
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @public
|
|
55
|
+
* @since 0.6.0
|
|
8
56
|
*/
|
|
9
|
-
interface
|
|
10
|
-
|
|
57
|
+
interface BlockerConfig {
|
|
58
|
+
scope?: string | ReadonlyArray<string>;
|
|
59
|
+
reason?: string;
|
|
60
|
+
/** Priority level (negative values are normalized to 0) */
|
|
61
|
+
priority?: number;
|
|
62
|
+
timestamp?: number;
|
|
63
|
+
/** Automatically remove the blocker after N milliseconds */
|
|
11
64
|
timeout?: number;
|
|
12
65
|
/** Callback invoked when the blocker is automatically removed due to timeout */
|
|
13
66
|
onTimeout?: (blockerId: string) => void;
|
|
14
67
|
}
|
|
15
68
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* Creates a wrapper function that automatically:
|
|
19
|
-
* 1. Adds a blocker before executing the async function
|
|
20
|
-
* 2. Executes the async function
|
|
21
|
-
* 3. Removes the blocker after completion (success or failure)
|
|
69
|
+
* Internal representation of a blocker with all fields populated.
|
|
22
70
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* The blocker is removed even if the async function throws an error.
|
|
71
|
+
* This is the stored format in the Map. All optional fields from {@link BlockerConfig}
|
|
72
|
+
* are converted to required fields with default values applied.
|
|
26
73
|
*
|
|
27
|
-
*
|
|
74
|
+
* @internal This type is primarily for internal use. Users should work with
|
|
75
|
+
* {@link BlockerConfig} for configuration and {@link BlockerInfo} for
|
|
76
|
+
* reading blocker data.
|
|
28
77
|
*
|
|
29
|
-
* @
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
78
|
+
* @since 0.6.0
|
|
79
|
+
*/
|
|
80
|
+
interface StoredBlocker {
|
|
81
|
+
scope: string | ReadonlyArray<string>;
|
|
82
|
+
reason: string;
|
|
83
|
+
priority: number;
|
|
84
|
+
timestamp: number;
|
|
85
|
+
/** Timeout duration in milliseconds (if set) */
|
|
86
|
+
timeout?: number;
|
|
87
|
+
/** Internal timeout ID for cleanup */
|
|
88
|
+
timeoutId?: ReturnType<typeof setTimeout>;
|
|
89
|
+
/** Callback invoked when the blocker is automatically removed due to timeout */
|
|
90
|
+
onTimeout?: (blockerId: string) => void;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Complete blocker information including its unique identifier.
|
|
37
94
|
*
|
|
38
|
-
*
|
|
95
|
+
* This type extends {@link StoredBlocker} with the blocker's ID, making it
|
|
96
|
+
* suitable for reading and displaying blocker information. Returned by
|
|
97
|
+
* {@link UIBlockingStoreActions.getBlockingInfo} and used by {@link useBlockingInfo}.
|
|
39
98
|
*
|
|
40
99
|
* @example
|
|
41
|
-
*
|
|
42
|
-
* ```
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
100
|
+
* Accessing blocker info
|
|
101
|
+
* ```ts
|
|
102
|
+
* const blockers: BlockerInfo[] = store.getState().getBlockingInfo('form');
|
|
103
|
+
* blockers.forEach(blocker => {
|
|
104
|
+
* console.log(`${blocker.id}: ${blocker.reason} (priority: ${blocker.priority})`);
|
|
105
|
+
* });
|
|
106
|
+
* ```
|
|
48
107
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
108
|
+
* @public
|
|
109
|
+
* @since 0.6.0
|
|
110
|
+
*/
|
|
111
|
+
interface BlockerInfo extends Omit<StoredBlocker, "timeoutId"> {
|
|
112
|
+
id: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Internal state structure of the UI blocking store.
|
|
56
116
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
117
|
+
* Contains the core data structures for managing blockers and middleware.
|
|
118
|
+
* This state is combined with {@link UIBlockingStoreActions} to create the
|
|
119
|
+
* complete {@link UIBlockingStore} type.
|
|
59
120
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
|
|
121
|
+
* @internal
|
|
122
|
+
* @since 0.6.0
|
|
123
|
+
*/
|
|
124
|
+
interface UIBlockingStoreState {
|
|
125
|
+
activeBlockers: Map<string, StoredBlocker>;
|
|
126
|
+
middlewares: Map<string, Middleware>;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* All available actions for managing UI blocking state.
|
|
63
130
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* const executeWithBlocking = useAsyncAction(
|
|
68
|
-
* 'fetchData',
|
|
69
|
-
* ['global', 'data'],
|
|
70
|
-
* {
|
|
71
|
-
* timeout: 30000, // 30 seconds
|
|
72
|
-
* onTimeout: (blockerId) => {
|
|
73
|
-
* console.warn(`Operation ${blockerId} timed out`);
|
|
74
|
-
* }
|
|
75
|
-
* }
|
|
76
|
-
* );
|
|
131
|
+
* These methods allow adding, removing, updating blockers, checking blocking status,
|
|
132
|
+
* and managing middleware. Combined with {@link UIBlockingStoreState} to form
|
|
133
|
+
* the complete {@link UIBlockingStore} type.
|
|
77
134
|
*
|
|
78
|
-
*
|
|
79
|
-
* try {
|
|
80
|
-
* const data = await executeWithBlocking(async () => {
|
|
81
|
-
* return await fetchDataFromAPI();
|
|
82
|
-
* });
|
|
83
|
-
* setData(data);
|
|
84
|
-
* } catch (error) {
|
|
85
|
-
* console.error('Failed to load data:', error);
|
|
86
|
-
* // Blocker is automatically removed even on error
|
|
87
|
-
* }
|
|
88
|
-
* };
|
|
89
|
-
* ```
|
|
135
|
+
* All actions are safe to call multiple times and handle edge cases gracefully.
|
|
90
136
|
*
|
|
91
137
|
* @example
|
|
92
|
-
*
|
|
93
|
-
* ```
|
|
94
|
-
*
|
|
95
|
-
* const uploadWithBlocking = useAsyncAction('upload', 'uploads');
|
|
138
|
+
* Using store actions directly
|
|
139
|
+
* ```ts
|
|
140
|
+
* import { uiBlockingStoreApi } from '@okyrychenko-dev/react-action-guard';
|
|
96
141
|
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
142
|
+
* // Add a blocker
|
|
143
|
+
* uiBlockingStoreApi.getState().addBlocker('my-blocker', {
|
|
144
|
+
* scope: 'form',
|
|
145
|
+
* reason: 'Processing...'
|
|
146
|
+
* });
|
|
102
147
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
148
|
+
* // Check if blocked
|
|
149
|
+
* const isBlocked = uiBlockingStoreApi.getState().isBlocked('form');
|
|
105
150
|
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
151
|
+
* // Remove blocker
|
|
152
|
+
* uiBlockingStoreApi.getState().removeBlocker('my-blocker');
|
|
108
153
|
* ```
|
|
109
154
|
*
|
|
155
|
+
* @public
|
|
156
|
+
* @since 0.6.0
|
|
157
|
+
*/
|
|
158
|
+
interface UIBlockingStoreActions {
|
|
159
|
+
addBlocker: (id: string, config?: BlockerConfig) => void;
|
|
160
|
+
updateBlocker: (id: string, config?: Partial<BlockerConfig>) => void;
|
|
161
|
+
removeBlocker: (id: string) => void;
|
|
162
|
+
isBlocked: (scope?: string | ReadonlyArray<string>) => boolean;
|
|
163
|
+
getBlockingInfo: (scope: string) => ReadonlyArray<BlockerInfo>;
|
|
164
|
+
clearAllBlockers: VoidFunction;
|
|
165
|
+
clearBlockersForScope: (scope: string) => void;
|
|
166
|
+
registerMiddleware: (name: string, middleware: Middleware) => void;
|
|
167
|
+
unregisterMiddleware: (name: string) => void;
|
|
168
|
+
runMiddlewares: (context: MiddlewareContext) => Promise<void>;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Complete UI blocking store type combining state and actions.
|
|
172
|
+
*
|
|
173
|
+
* This is the full store interface used by hooks like {@link useUIBlockingStore}
|
|
174
|
+
* and accessible via {@link uiBlockingStoreApi}. It combines all state properties
|
|
175
|
+
* from {@link UIBlockingStoreState} with all action methods from {@link UIBlockingStoreActions}.
|
|
176
|
+
*
|
|
110
177
|
* @example
|
|
111
|
-
*
|
|
112
|
-
* ```
|
|
113
|
-
*
|
|
114
|
-
* id: string;
|
|
115
|
-
* name: string;
|
|
116
|
-
* }
|
|
178
|
+
* Using the complete store
|
|
179
|
+
* ```ts
|
|
180
|
+
* import { useUIBlockingStore } from '@okyrychenko-dev/react-action-guard';
|
|
117
181
|
*
|
|
118
|
-
* function
|
|
119
|
-
* const
|
|
182
|
+
* function MyComponent() {
|
|
183
|
+
* const store = useUIBlockingStore();
|
|
120
184
|
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* const response = await fetch(`/api/users/${userId}`);
|
|
124
|
-
* return response.json(); // TypeScript knows this is UserData
|
|
125
|
-
* });
|
|
185
|
+
* // Access state
|
|
186
|
+
* console.log(store.activeBlockers.size);
|
|
126
187
|
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* };
|
|
188
|
+
* // Call actions
|
|
189
|
+
* store.addBlocker('my-blocker', { scope: 'form' });
|
|
130
190
|
*
|
|
131
|
-
* return
|
|
191
|
+
* return <div>...</div>;
|
|
132
192
|
* }
|
|
133
193
|
* ```
|
|
134
194
|
*
|
|
135
|
-
* @see {@link useBlocker} for manual blocker management
|
|
136
|
-
* @see {@link useIsBlocked} to check blocking state
|
|
137
|
-
* @see {@link UseAsyncActionOptions} for available options
|
|
138
|
-
*
|
|
139
195
|
* @public
|
|
140
196
|
* @since 0.6.0
|
|
141
197
|
*/
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
interface MixpanelConfig {
|
|
150
|
-
provider: "mixpanel";
|
|
151
|
-
}
|
|
152
|
-
interface AmplitudeConfig {
|
|
153
|
-
provider: "amplitude";
|
|
154
|
-
}
|
|
155
|
-
interface CustomAnalyticsConfig {
|
|
156
|
-
track: (event: string, data: AnalyticsEventData) => void;
|
|
198
|
+
type UIBlockingStore = UIBlockingStoreState & UIBlockingStoreActions;
|
|
199
|
+
interface ShallowStoreBindings<StoreState> {
|
|
200
|
+
useStore: {
|
|
201
|
+
(): StoreState;
|
|
202
|
+
<T>(selector: (state: StoreState) => T): T;
|
|
203
|
+
};
|
|
204
|
+
useStoreApi: StoreApi<StoreState>;
|
|
157
205
|
}
|
|
158
|
-
|
|
206
|
+
|
|
207
|
+
declare const uiBlockingStoreApi: Omit<zustand.StoreApi<UIBlockingStore>, "setState" | "devtools"> & {
|
|
208
|
+
setState(partial: UIBlockingStore | Partial<UIBlockingStore> | ((state: UIBlockingStore) => UIBlockingStore | Partial<UIBlockingStore>), replace?: false | undefined, action?: (string | {
|
|
209
|
+
[x: string]: unknown;
|
|
210
|
+
[x: number]: unknown;
|
|
211
|
+
[x: symbol]: unknown;
|
|
212
|
+
type: string;
|
|
213
|
+
}) | undefined): void;
|
|
214
|
+
setState(state: UIBlockingStore | ((state: UIBlockingStore) => UIBlockingStore), replace: true, action?: (string | {
|
|
215
|
+
[x: string]: unknown;
|
|
216
|
+
[x: number]: unknown;
|
|
217
|
+
[x: symbol]: unknown;
|
|
218
|
+
type: string;
|
|
219
|
+
}) | undefined): void;
|
|
220
|
+
devtools: {
|
|
221
|
+
cleanup: () => void;
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
declare function useUIBlockingStore(): UIBlockingStore;
|
|
225
|
+
declare function useUIBlockingStore<T>(selector: (state: UIBlockingStore) => T, equalityFn?: (a: T, b: T) => boolean): T;
|
|
159
226
|
|
|
160
227
|
type BlockingAction = "add" | "update" | "remove" | "timeout" | "clear" | "clear_scope";
|
|
161
228
|
type MiddlewareBlockerConfig = BlockerConfig;
|
|
@@ -369,12 +436,12 @@ interface PerformanceConfig {
|
|
|
369
436
|
/**
|
|
370
437
|
* Creates middleware for monitoring blocker performance and detecting slow blocks.
|
|
371
438
|
*
|
|
372
|
-
* Tracks the duration of each blocker (from add to remove) and
|
|
373
|
-
* exceeds the configured threshold. Useful for identifying
|
|
374
|
-
* stuck blockers, or operations that take too long.
|
|
439
|
+
* Tracks the duration of each blocker (from add to remove) and invokes an optional
|
|
440
|
+
* callback when a blocker exceeds the configured threshold. Useful for identifying
|
|
441
|
+
* performance issues, stuck blockers, or operations that take too long.
|
|
375
442
|
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
443
|
+
* The middleware is side-effect free by default; use `onSlowBlock` for custom
|
|
444
|
+
* reporting, logging, or analytics integration.
|
|
378
445
|
*
|
|
379
446
|
* @param config - Performance monitoring configuration
|
|
380
447
|
* @param config.slowBlockThreshold - Duration in ms before considering a block "slow".
|
|
@@ -392,7 +459,7 @@ interface PerformanceConfig {
|
|
|
392
459
|
* const performanceMiddleware = createPerformanceMiddleware();
|
|
393
460
|
*
|
|
394
461
|
* configureMiddleware([performanceMiddleware]);
|
|
395
|
-
* //
|
|
462
|
+
* // Track slow blocks via onSlowBlock if any blocker lasts > 3 seconds
|
|
396
463
|
* ```
|
|
397
464
|
*
|
|
398
465
|
* @example
|
|
@@ -454,202 +521,290 @@ interface PerformanceConfig {
|
|
|
454
521
|
declare function createPerformanceMiddleware(config?: PerformanceConfig): Middleware;
|
|
455
522
|
|
|
456
523
|
/**
|
|
457
|
-
*
|
|
524
|
+
* Props for the {@link UIBlockingProvider} component.
|
|
458
525
|
*
|
|
459
|
-
*
|
|
460
|
-
* -
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
526
|
+
* Configures an isolated UI blocking store instance for a subtree of your app.
|
|
527
|
+
* Useful for SSR, testing, micro-frontends, or any scenario where you need
|
|
528
|
+
* independent blocking state.
|
|
529
|
+
*
|
|
530
|
+
* @public
|
|
531
|
+
* @since 0.6.0
|
|
532
|
+
*/
|
|
533
|
+
interface UIBlockingProviderProps {
|
|
534
|
+
children: ReactNode;
|
|
535
|
+
/** Enable Redux DevTools integration (default: true in development) */
|
|
536
|
+
enableDevtools?: boolean;
|
|
537
|
+
/** Name for Redux DevTools (default: "UIBlocking") */
|
|
538
|
+
devtoolsName?: string;
|
|
539
|
+
/** Initial middlewares to register */
|
|
540
|
+
middlewares?: ReadonlyArray<Middleware>;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Base provider implementation created using toolkit's createStoreProvider.
|
|
544
|
+
* @internal
|
|
545
|
+
*/
|
|
546
|
+
declare const useUIBlockingContext: () => StoreApi<UIBlockingStore>;
|
|
547
|
+
declare const useIsInsideUIBlockingProvider: () => boolean;
|
|
548
|
+
declare const useOptionalUIBlockingContext: () => StoreApi<UIBlockingStore> | null;
|
|
549
|
+
declare function useUIBlockingStoreFromContext(): UIBlockingStore;
|
|
550
|
+
declare function useUIBlockingStoreFromContext<T>(selector: (state: UIBlockingStore) => T, equalityFn?: (a: T, b: T) => boolean): T;
|
|
551
|
+
/**
|
|
552
|
+
* Provider component for isolated UI blocking state management.
|
|
553
|
+
*
|
|
554
|
+
* Creates an independent store instance for a subtree of your application.
|
|
555
|
+
* Each provider has its own isolated blocking state, separate from the global
|
|
556
|
+
* store and other provider instances.
|
|
557
|
+
*
|
|
558
|
+
* **Use cases:**
|
|
559
|
+
* - Server-Side Rendering (SSR) - Avoid state sharing between requests
|
|
560
|
+
* - Testing - Isolated state for each test
|
|
561
|
+
* - Micro-frontends - Independent blocking state per micro-app
|
|
562
|
+
* - Modals/Dialogs - Scoped blocking within a dialog
|
|
563
|
+
*
|
|
564
|
+
* Uses `createStoreProvider` from `@okyrychenko-dev/react-zustand-toolkit` with
|
|
565
|
+
* built-in DevTools support and middleware registration.
|
|
566
|
+
*
|
|
567
|
+
* @param props - Provider configuration
|
|
568
|
+
* @param props.children - React children to wrap with the provider
|
|
569
|
+
* @param props.enableDevtools - Enable Redux DevTools integration. Defaults to true in development, false in production.
|
|
570
|
+
* @param props.devtoolsName - Name displayed in Redux DevTools. Defaults to "UIBlocking".
|
|
571
|
+
* @param props.middlewares - Array of middleware functions to register on store creation
|
|
464
572
|
*
|
|
465
573
|
* @example
|
|
466
|
-
* Basic
|
|
467
|
-
* ```
|
|
468
|
-
*
|
|
469
|
-
*
|
|
470
|
-
*
|
|
471
|
-
*
|
|
472
|
-
*
|
|
574
|
+
* Basic SSR setup
|
|
575
|
+
* ```tsx
|
|
576
|
+
* import { UIBlockingProvider } from '@okyrychenko-dev/react-action-guard';
|
|
577
|
+
*
|
|
578
|
+
* function App() {
|
|
579
|
+
* return (
|
|
580
|
+
* <UIBlockingProvider>
|
|
581
|
+
* <MyApplication />
|
|
582
|
+
* </UIBlockingProvider>
|
|
583
|
+
* );
|
|
584
|
+
* }
|
|
473
585
|
* ```
|
|
474
586
|
*
|
|
475
587
|
* @example
|
|
476
|
-
* With
|
|
477
|
-
* ```
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
485
|
-
*
|
|
486
|
-
*
|
|
588
|
+
* With middleware and custom DevTools name
|
|
589
|
+
* ```tsx
|
|
590
|
+
* import { UIBlockingProvider, loggerMiddleware } from '@okyrychenko-dev/react-action-guard';
|
|
591
|
+
*
|
|
592
|
+
* function App() {
|
|
593
|
+
* return (
|
|
594
|
+
* <UIBlockingProvider
|
|
595
|
+
* enableDevtools={true}
|
|
596
|
+
* devtoolsName="MyApp-UIBlocking"
|
|
597
|
+
* middlewares={[loggerMiddleware]}
|
|
598
|
+
* >
|
|
599
|
+
* <MyApplication />
|
|
600
|
+
* </UIBlockingProvider>
|
|
601
|
+
* );
|
|
602
|
+
* }
|
|
487
603
|
* ```
|
|
488
604
|
*
|
|
605
|
+
* @example
|
|
606
|
+
* Multiple providers for micro-frontends
|
|
607
|
+
* ```tsx
|
|
608
|
+
* function MicroFrontendApp() {
|
|
609
|
+
* return (
|
|
610
|
+
* <div>
|
|
611
|
+
* <UIBlockingProvider devtoolsName="MicroApp1">
|
|
612
|
+
* <MicroApp1 />
|
|
613
|
+
* </UIBlockingProvider>
|
|
614
|
+
*
|
|
615
|
+
* <UIBlockingProvider devtoolsName="MicroApp2">
|
|
616
|
+
* <MicroApp2 />
|
|
617
|
+
* </UIBlockingProvider>
|
|
618
|
+
* </div>
|
|
619
|
+
* );
|
|
620
|
+
* }
|
|
621
|
+
* ```
|
|
622
|
+
*
|
|
623
|
+
* @example
|
|
624
|
+
* Testing with isolated state
|
|
625
|
+
* ```tsx
|
|
626
|
+
* // In your test file
|
|
627
|
+
* import { render } from '@testing-library/react';
|
|
628
|
+
* import { UIBlockingProvider } from '@okyrychenko-dev/react-action-guard';
|
|
629
|
+
*
|
|
630
|
+
* test('blocker behavior', () => {
|
|
631
|
+
* render(
|
|
632
|
+
* <UIBlockingProvider enableDevtools={false}>
|
|
633
|
+
* <ComponentUnderTest />
|
|
634
|
+
* </UIBlockingProvider>
|
|
635
|
+
* );
|
|
636
|
+
* // Each test gets isolated state
|
|
637
|
+
* });
|
|
638
|
+
* ```
|
|
639
|
+
*
|
|
640
|
+
* @see {@link useUIBlockingContext} to access the store from context
|
|
641
|
+
* @see {@link useIsInsideUIBlockingProvider} to check if inside a provider
|
|
642
|
+
* @see {@link UIBlockingProviderProps} for prop details
|
|
643
|
+
*
|
|
489
644
|
* @public
|
|
490
645
|
* @since 0.6.0
|
|
491
646
|
*/
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
reason?: string;
|
|
495
|
-
/** Priority level (negative values are normalized to 0) */
|
|
496
|
-
priority?: number;
|
|
497
|
-
timestamp?: number;
|
|
498
|
-
/** Automatically remove the blocker after N milliseconds */
|
|
499
|
-
timeout?: number;
|
|
500
|
-
/** Callback invoked when the blocker is automatically removed due to timeout */
|
|
501
|
-
onTimeout?: (blockerId: string) => void;
|
|
502
|
-
}
|
|
647
|
+
declare function UIBlockingProvider({ children, enableDevtools, devtoolsName, middlewares, }: UIBlockingProviderProps): ReactNode;
|
|
648
|
+
|
|
503
649
|
/**
|
|
504
|
-
*
|
|
650
|
+
* Hook that resolves to either the context store or global store
|
|
505
651
|
*
|
|
506
|
-
* This
|
|
507
|
-
*
|
|
652
|
+
* This hook automatically uses the store from UIBlockingProvider if available,
|
|
653
|
+
* otherwise falls back to the global store. This enables both patterns:
|
|
508
654
|
*
|
|
509
|
-
*
|
|
510
|
-
*
|
|
511
|
-
* reading blocker data.
|
|
655
|
+
* 1. Global store (default behavior, no Provider needed)
|
|
656
|
+
* 2. Context store (for SSR, testing, micro-frontends)
|
|
512
657
|
*
|
|
513
|
-
* @
|
|
658
|
+
* @returns The resolved store API
|
|
514
659
|
*/
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
660
|
+
declare function useResolvedStoreApi(): StoreApi<UIBlockingStore>;
|
|
661
|
+
/**
|
|
662
|
+
* Hook to use the resolved store with a selector
|
|
663
|
+
*
|
|
664
|
+
* Automatically applies shallow comparison to prevent unnecessary re-renders.
|
|
665
|
+
*
|
|
666
|
+
* @param selector - Selector function to pick state from the store
|
|
667
|
+
* @returns Selected state value
|
|
668
|
+
*/
|
|
669
|
+
declare function useResolvedValue<T>(selector: (state: UIBlockingStore) => T): T;
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Options for useAsyncAction hook
|
|
673
|
+
*/
|
|
674
|
+
interface UseAsyncActionOptions {
|
|
675
|
+
/** Timeout in milliseconds after which the blocker will be automatically removed */
|
|
521
676
|
timeout?: number;
|
|
522
|
-
/** Internal timeout ID for cleanup */
|
|
523
|
-
timeoutId?: ReturnType<typeof setTimeout>;
|
|
524
677
|
/** Callback invoked when the blocker is automatically removed due to timeout */
|
|
525
678
|
onTimeout?: (blockerId: string) => void;
|
|
526
679
|
}
|
|
527
680
|
/**
|
|
528
|
-
*
|
|
681
|
+
* Wraps async functions with automatic UI blocking during execution.
|
|
529
682
|
*
|
|
530
|
-
*
|
|
531
|
-
*
|
|
532
|
-
*
|
|
683
|
+
* Creates a wrapper function that automatically:
|
|
684
|
+
* 1. Adds a blocker before executing the async function
|
|
685
|
+
* 2. Executes the async function
|
|
686
|
+
* 3. Removes the blocker after completion (success or failure)
|
|
533
687
|
*
|
|
534
|
-
*
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
* const blockers: BlockerInfo[] = store.getState().getBlockingInfo('form');
|
|
538
|
-
* blockers.forEach(blocker => {
|
|
539
|
-
* console.log(`${blocker.id}: ${blocker.reason} (priority: ${blocker.priority})`);
|
|
540
|
-
* });
|
|
541
|
-
* ```
|
|
688
|
+
* Each invocation generates a unique blocker ID (actionId-counter), allowing
|
|
689
|
+
* multiple concurrent executions of the same action without ID conflicts.
|
|
690
|
+
* The blocker is removed even if the async function throws an error.
|
|
542
691
|
*
|
|
543
|
-
*
|
|
544
|
-
* @since 0.6.0
|
|
545
|
-
*/
|
|
546
|
-
interface BlockerInfo extends StoredBlocker {
|
|
547
|
-
id: string;
|
|
548
|
-
}
|
|
549
|
-
/**
|
|
550
|
-
* Internal state structure of the UI blocking store.
|
|
692
|
+
* Works with both the global store and isolated provider instances (via UIBlockingProvider).
|
|
551
693
|
*
|
|
552
|
-
*
|
|
553
|
-
*
|
|
554
|
-
*
|
|
694
|
+
* @template T - The return type of the async function being wrapped
|
|
695
|
+
* @param actionId - Base identifier for the action. Used in blocker ID and default reason.
|
|
696
|
+
* Example: "saveForm", "fetchData", "submitOrder"
|
|
697
|
+
* @param scope - Scope(s) to block during execution. Can be a single scope or array.
|
|
698
|
+
* Defaults to "global" if not specified.
|
|
699
|
+
* @param options - Optional configuration
|
|
700
|
+
* @param options.timeout - Timeout in milliseconds. Blocker auto-removes after this duration.
|
|
701
|
+
* @param options.onTimeout - Callback invoked when blocker times out before async completes
|
|
702
|
+
*
|
|
703
|
+
* @returns Wrapper function that accepts an async function and returns a Promise with the same type
|
|
704
|
+
*
|
|
705
|
+
* @example
|
|
706
|
+
* Basic form submission
|
|
707
|
+
* ```tsx
|
|
708
|
+
* function MyForm() {
|
|
709
|
+
* const executeWithBlocking = useAsyncAction('saveForm', 'form');
|
|
710
|
+
*
|
|
711
|
+
* const handleSubmit = async (e) => {
|
|
712
|
+
* e.preventDefault();
|
|
555
713
|
*
|
|
556
|
-
*
|
|
557
|
-
*
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
}
|
|
563
|
-
/**
|
|
564
|
-
* All available actions for managing UI blocking state.
|
|
714
|
+
* await executeWithBlocking(async () => {
|
|
715
|
+
* const response = await fetch('/api/save', {
|
|
716
|
+
* method: 'POST',
|
|
717
|
+
* body: JSON.stringify(formData)
|
|
718
|
+
* });
|
|
719
|
+
* return response.json();
|
|
720
|
+
* });
|
|
565
721
|
*
|
|
566
|
-
*
|
|
567
|
-
*
|
|
568
|
-
* the complete {@link UIBlockingStore} type.
|
|
722
|
+
* alert('Form saved!');
|
|
723
|
+
* };
|
|
569
724
|
*
|
|
570
|
-
*
|
|
725
|
+
* return <form onSubmit={handleSubmit}>...</form>;
|
|
726
|
+
* }
|
|
727
|
+
* ```
|
|
571
728
|
*
|
|
572
729
|
* @example
|
|
573
|
-
*
|
|
574
|
-
* ```
|
|
575
|
-
*
|
|
730
|
+
* With timeout and error handling
|
|
731
|
+
* ```tsx
|
|
732
|
+
* const executeWithBlocking = useAsyncAction(
|
|
733
|
+
* 'fetchData',
|
|
734
|
+
* ['global', 'data'],
|
|
735
|
+
* {
|
|
736
|
+
* timeout: 30000, // 30 seconds
|
|
737
|
+
* onTimeout: (blockerId) => {
|
|
738
|
+
* console.warn(`Operation ${blockerId} timed out`);
|
|
739
|
+
* }
|
|
740
|
+
* }
|
|
741
|
+
* );
|
|
576
742
|
*
|
|
577
|
-
*
|
|
578
|
-
*
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
743
|
+
* const loadData = async () => {
|
|
744
|
+
* try {
|
|
745
|
+
* const data = await executeWithBlocking(async () => {
|
|
746
|
+
* return await fetchDataFromAPI();
|
|
747
|
+
* });
|
|
748
|
+
* setData(data);
|
|
749
|
+
* } catch (error) {
|
|
750
|
+
* console.error('Failed to load data:', error);
|
|
751
|
+
* // Blocker is automatically removed even on error
|
|
752
|
+
* }
|
|
753
|
+
* };
|
|
754
|
+
* ```
|
|
582
755
|
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
756
|
+
* @example
|
|
757
|
+
* Multiple concurrent actions
|
|
758
|
+
* ```tsx
|
|
759
|
+
* function FileUploader() {
|
|
760
|
+
* const uploadWithBlocking = useAsyncAction('upload', 'uploads');
|
|
585
761
|
*
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
*
|
|
762
|
+
* const uploadFiles = async (files) => {
|
|
763
|
+
* // Each upload gets unique blocker ID (upload-1, upload-2, etc.)
|
|
764
|
+
* const promises = files.map(file =>
|
|
765
|
+
* uploadWithBlocking(() => uploadFile(file))
|
|
766
|
+
* );
|
|
589
767
|
*
|
|
590
|
-
*
|
|
591
|
-
*
|
|
592
|
-
*/
|
|
593
|
-
interface UIBlockingStoreActions {
|
|
594
|
-
addBlocker: (id: string, config?: BlockerConfig) => void;
|
|
595
|
-
updateBlocker: (id: string, config?: Partial<BlockerConfig>) => void;
|
|
596
|
-
removeBlocker: (id: string) => void;
|
|
597
|
-
isBlocked: (scope?: string | ReadonlyArray<string>) => boolean;
|
|
598
|
-
getBlockingInfo: (scope: string) => ReadonlyArray<BlockerInfo>;
|
|
599
|
-
clearAllBlockers: VoidFunction;
|
|
600
|
-
clearBlockersForScope: (scope: string) => void;
|
|
601
|
-
registerMiddleware: (name: string, middleware: Middleware) => void;
|
|
602
|
-
unregisterMiddleware: (name: string) => void;
|
|
603
|
-
runMiddlewares: (context: MiddlewareContext) => Promise<void>;
|
|
604
|
-
}
|
|
605
|
-
/**
|
|
606
|
-
* Complete UI blocking store type combining state and actions.
|
|
768
|
+
* await Promise.all(promises);
|
|
769
|
+
* };
|
|
607
770
|
*
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
771
|
+
* return <...>;
|
|
772
|
+
* }
|
|
773
|
+
* ```
|
|
611
774
|
*
|
|
612
775
|
* @example
|
|
613
|
-
*
|
|
614
|
-
* ```
|
|
615
|
-
*
|
|
776
|
+
* Type-safe return value
|
|
777
|
+
* ```tsx
|
|
778
|
+
* interface UserData {
|
|
779
|
+
* id: string;
|
|
780
|
+
* name: string;
|
|
781
|
+
* }
|
|
616
782
|
*
|
|
617
|
-
* function
|
|
618
|
-
* const
|
|
783
|
+
* function UserProfile() {
|
|
784
|
+
* const executeWithBlocking = useAsyncAction<UserData>('fetchUser', 'user');
|
|
619
785
|
*
|
|
620
|
-
*
|
|
621
|
-
*
|
|
786
|
+
* const loadUser = async (userId: string) => {
|
|
787
|
+
* const userData = await executeWithBlocking(async () => {
|
|
788
|
+
* const response = await fetch(`/api/users/${userId}`);
|
|
789
|
+
* return response.json(); // TypeScript knows this is UserData
|
|
790
|
+
* });
|
|
622
791
|
*
|
|
623
|
-
*
|
|
624
|
-
*
|
|
792
|
+
* // userData is typed as UserData
|
|
793
|
+
* console.log(userData.name);
|
|
794
|
+
* };
|
|
625
795
|
*
|
|
626
|
-
* return
|
|
796
|
+
* return <...>;
|
|
627
797
|
* }
|
|
628
798
|
* ```
|
|
629
799
|
*
|
|
800
|
+
* @see {@link useBlocker} for manual blocker management
|
|
801
|
+
* @see {@link useIsBlocked} to check blocking state
|
|
802
|
+
* @see {@link UseAsyncActionOptions} for available options
|
|
803
|
+
*
|
|
630
804
|
* @public
|
|
631
805
|
* @since 0.6.0
|
|
632
806
|
*/
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* UI Blocking Store
|
|
637
|
-
*
|
|
638
|
-
* Global Zustand store for managing UI blocking state across the application.
|
|
639
|
-
*
|
|
640
|
-
* Features:
|
|
641
|
-
* - Priority-based blocking system
|
|
642
|
-
* - Scope-based blocking (global, specific areas, or multiple scopes)
|
|
643
|
-
* - Automatic cleanup on unmount (when using hooks)
|
|
644
|
-
* - DevTools integration for debugging
|
|
645
|
-
* - Automatic shallow comparison for selectors
|
|
646
|
-
*
|
|
647
|
-
*/
|
|
648
|
-
declare const useUIBlockingStore: {
|
|
649
|
-
(): UIBlockingStore;
|
|
650
|
-
<T>(selector: (state: UIBlockingStore) => T): T;
|
|
651
|
-
};
|
|
652
|
-
declare const uiBlockingStoreApi: zustand.StoreApi<UIBlockingStore>;
|
|
807
|
+
declare function useAsyncAction<T = unknown>(actionId: string, scope?: string | ReadonlyArray<string>, options?: UseAsyncActionOptions): (asyncFn: () => Promise<T>) => Promise<T>;
|
|
653
808
|
|
|
654
809
|
/**
|
|
655
810
|
* Automatically manages a UI blocker based on component lifecycle.
|
|
@@ -948,16 +1103,10 @@ interface ConditionalBlockerConfig<TState = unknown> extends Omit<BlockerConfig,
|
|
|
948
1103
|
* Without state parameter (simple condition)
|
|
949
1104
|
* ```tsx
|
|
950
1105
|
* useConditionalBlocker('low-battery', {
|
|
951
|
-
* condition: () =>
|
|
952
|
-
* // Check battery level if available
|
|
953
|
-
* if ('getBattery' in navigator) {
|
|
954
|
-
* return navigator.getBattery().then(b => b.level < 0.05);
|
|
955
|
-
* }
|
|
956
|
-
* return false;
|
|
957
|
-
* },
|
|
1106
|
+
* condition: () => !navigator.onLine,
|
|
958
1107
|
* checkInterval: 30000, // Check every 30 seconds
|
|
959
1108
|
* scope: 'heavy-operations',
|
|
960
|
-
* reason: '
|
|
1109
|
+
* reason: 'Internet connection is required for this operation',
|
|
961
1110
|
* priority: 80
|
|
962
1111
|
* });
|
|
963
1112
|
* ```
|
|
@@ -1442,130 +1591,16 @@ interface TypedHooks<TScope extends string> {
|
|
|
1442
1591
|
declare function createTypedHooks<TScope extends string>(): TypedHooks<TScope>;
|
|
1443
1592
|
|
|
1444
1593
|
/**
|
|
1445
|
-
*
|
|
1446
|
-
*
|
|
1447
|
-
* Configures an isolated UI blocking store instance for a subtree of your app.
|
|
1448
|
-
* Useful for SSR, testing, micro-frontends, or any scenario where you need
|
|
1449
|
-
* independent blocking state.
|
|
1450
|
-
*
|
|
1451
|
-
* @public
|
|
1452
|
-
* @since 0.6.0
|
|
1594
|
+
* @deprecated Use `useOptionalUIBlockingContext`.
|
|
1453
1595
|
*/
|
|
1454
|
-
|
|
1455
|
-
children: ReactNode;
|
|
1456
|
-
/** Enable Redux DevTools integration (default: true in development) */
|
|
1457
|
-
enableDevtools?: boolean;
|
|
1458
|
-
/** Name for Redux DevTools (default: "UIBlocking") */
|
|
1459
|
-
devtoolsName?: string;
|
|
1460
|
-
/** Initial middlewares to register */
|
|
1461
|
-
middlewares?: ReadonlyArray<Middleware>;
|
|
1462
|
-
}
|
|
1596
|
+
declare function useOptionalContext(): ReturnType<typeof useOptionalUIBlockingContext>;
|
|
1463
1597
|
/**
|
|
1464
|
-
*
|
|
1465
|
-
* @internal
|
|
1598
|
+
* @deprecated Use `useResolvedStoreApi`.
|
|
1466
1599
|
*/
|
|
1467
|
-
declare
|
|
1468
|
-
declare const useUIBlockingStoreFromContext: {
|
|
1469
|
-
(): UIBlockingStore;
|
|
1470
|
-
<T>(selector: (state: UIBlockingStore) => T): T;
|
|
1471
|
-
};
|
|
1472
|
-
declare const useIsInsideUIBlockingProvider: () => boolean;
|
|
1600
|
+
declare function useResolvedStore(): StoreApi<UIBlockingStore>;
|
|
1473
1601
|
/**
|
|
1474
|
-
*
|
|
1475
|
-
*
|
|
1476
|
-
* Creates an independent store instance for a subtree of your application.
|
|
1477
|
-
* Each provider has its own isolated blocking state, separate from the global
|
|
1478
|
-
* store and other provider instances.
|
|
1479
|
-
*
|
|
1480
|
-
* **Use cases:**
|
|
1481
|
-
* - Server-Side Rendering (SSR) - Avoid state sharing between requests
|
|
1482
|
-
* - Testing - Isolated state for each test
|
|
1483
|
-
* - Micro-frontends - Independent blocking state per micro-app
|
|
1484
|
-
* - Modals/Dialogs - Scoped blocking within a dialog
|
|
1485
|
-
*
|
|
1486
|
-
* Uses `createStoreProvider` from `@okyrychenko-dev/react-zustand-toolkit` with
|
|
1487
|
-
* built-in DevTools support and middleware registration.
|
|
1488
|
-
*
|
|
1489
|
-
* @param props - Provider configuration
|
|
1490
|
-
* @param props.children - React children to wrap with the provider
|
|
1491
|
-
* @param props.enableDevtools - Enable Redux DevTools integration. Defaults to true in development, false in production.
|
|
1492
|
-
* @param props.devtoolsName - Name displayed in Redux DevTools. Defaults to "UIBlocking".
|
|
1493
|
-
* @param props.middlewares - Array of middleware functions to register on store creation
|
|
1494
|
-
*
|
|
1495
|
-
* @example
|
|
1496
|
-
* Basic SSR setup
|
|
1497
|
-
* ```tsx
|
|
1498
|
-
* import { UIBlockingProvider } from '@okyrychenko-dev/react-action-guard';
|
|
1499
|
-
*
|
|
1500
|
-
* function App() {
|
|
1501
|
-
* return (
|
|
1502
|
-
* <UIBlockingProvider>
|
|
1503
|
-
* <MyApplication />
|
|
1504
|
-
* </UIBlockingProvider>
|
|
1505
|
-
* );
|
|
1506
|
-
* }
|
|
1507
|
-
* ```
|
|
1508
|
-
*
|
|
1509
|
-
* @example
|
|
1510
|
-
* With middleware and custom DevTools name
|
|
1511
|
-
* ```tsx
|
|
1512
|
-
* import { UIBlockingProvider, loggerMiddleware } from '@okyrychenko-dev/react-action-guard';
|
|
1513
|
-
*
|
|
1514
|
-
* function App() {
|
|
1515
|
-
* return (
|
|
1516
|
-
* <UIBlockingProvider
|
|
1517
|
-
* enableDevtools={true}
|
|
1518
|
-
* devtoolsName="MyApp-UIBlocking"
|
|
1519
|
-
* middlewares={[loggerMiddleware]}
|
|
1520
|
-
* >
|
|
1521
|
-
* <MyApplication />
|
|
1522
|
-
* </UIBlockingProvider>
|
|
1523
|
-
* );
|
|
1524
|
-
* }
|
|
1525
|
-
* ```
|
|
1526
|
-
*
|
|
1527
|
-
* @example
|
|
1528
|
-
* Multiple providers for micro-frontends
|
|
1529
|
-
* ```tsx
|
|
1530
|
-
* function MicroFrontendApp() {
|
|
1531
|
-
* return (
|
|
1532
|
-
* <div>
|
|
1533
|
-
* <UIBlockingProvider devtoolsName="MicroApp1">
|
|
1534
|
-
* <MicroApp1 />
|
|
1535
|
-
* </UIBlockingProvider>
|
|
1536
|
-
*
|
|
1537
|
-
* <UIBlockingProvider devtoolsName="MicroApp2">
|
|
1538
|
-
* <MicroApp2 />
|
|
1539
|
-
* </UIBlockingProvider>
|
|
1540
|
-
* </div>
|
|
1541
|
-
* );
|
|
1542
|
-
* }
|
|
1543
|
-
* ```
|
|
1544
|
-
*
|
|
1545
|
-
* @example
|
|
1546
|
-
* Testing with isolated state
|
|
1547
|
-
* ```tsx
|
|
1548
|
-
* // In your test file
|
|
1549
|
-
* import { render } from '@testing-library/react';
|
|
1550
|
-
* import { UIBlockingProvider } from '@okyrychenko-dev/react-action-guard';
|
|
1551
|
-
*
|
|
1552
|
-
* test('blocker behavior', () => {
|
|
1553
|
-
* render(
|
|
1554
|
-
* <UIBlockingProvider enableDevtools={false}>
|
|
1555
|
-
* <ComponentUnderTest />
|
|
1556
|
-
* </UIBlockingProvider>
|
|
1557
|
-
* );
|
|
1558
|
-
* // Each test gets isolated state
|
|
1559
|
-
* });
|
|
1560
|
-
* ```
|
|
1561
|
-
*
|
|
1562
|
-
* @see {@link useUIBlockingContext} to access the store from context
|
|
1563
|
-
* @see {@link useIsInsideUIBlockingProvider} to check if inside a provider
|
|
1564
|
-
* @see {@link UIBlockingProviderProps} for prop details
|
|
1565
|
-
*
|
|
1566
|
-
* @public
|
|
1567
|
-
* @since 0.6.0
|
|
1602
|
+
* @deprecated Use `useResolvedValue`.
|
|
1568
1603
|
*/
|
|
1569
|
-
declare function
|
|
1604
|
+
declare function useResolvedStoreWithSelector<T>(selector: (state: UIBlockingStore) => T): T;
|
|
1570
1605
|
|
|
1571
|
-
export { type AmplitudeConfig, type AnalyticsConfig, type AnalyticsEventData, type AnalyticsProvider, type BlockerConfig, type BlockerConfigTyped, type BlockerInfo, type BlockingAction, type BlockingSchedule, type ConditionalBlockerConfig, type ConfirmDialogConfig, type ConfirmableBlockerConfig, type CustomAnalyticsConfig, type DefaultScopes, type GoogleAnalyticsConfig, type Middleware, type MiddlewareContext, type MixpanelConfig, type PerformanceConfig, type ScheduledBlockerConfig, type ScopeValue, type StoredBlocker, type TypedHooks, UIBlockingProvider, type UIBlockingProviderProps, type UIBlockingStore, type UIBlockingStoreActions, type UIBlockingStoreState, type UseAsyncActionOptions, type UseConfirmableBlockerReturn, configureMiddleware, createAnalyticsMiddleware, createPerformanceMiddleware, createTypedHooks, loggerMiddleware, uiBlockingStoreApi, useAsyncAction, useBlocker, useBlockingInfo, useConditionalBlocker, useConfirmableBlocker, useIsBlocked, useIsInsideUIBlockingProvider, useScheduledBlocker, useUIBlockingContext, useUIBlockingStore, useUIBlockingStoreFromContext };
|
|
1606
|
+
export { type AmplitudeConfig, type AnalyticsConfig, type AnalyticsEventData, type AnalyticsProvider, type BlockerConfig, type BlockerConfigTyped, type BlockerInfo, type BlockingAction, type BlockingSchedule, type ConditionalBlockerConfig, type ConfirmDialogConfig, type ConfirmableBlockerConfig, type CustomAnalyticsConfig, type DefaultScopes, type GoogleAnalyticsConfig, type Middleware, type MiddlewareContext, type MixpanelConfig, type PerformanceConfig, type ScheduledBlockerConfig, type ScopeValue, type ShallowStoreBindings, type StoredBlocker, type TypedHooks, UIBlockingProvider, type UIBlockingProviderProps, type UIBlockingStore, type UIBlockingStoreActions, type UIBlockingStoreState, type UseAsyncActionOptions, type UseConfirmableBlockerReturn, configureMiddleware, createAnalyticsMiddleware, createPerformanceMiddleware, createTypedHooks, loggerMiddleware, uiBlockingStoreApi, useAsyncAction, useBlocker, useBlockingInfo, useConditionalBlocker, useConfirmableBlocker, useIsBlocked, useIsInsideUIBlockingProvider, useOptionalContext, useOptionalUIBlockingContext, useResolvedStore, useResolvedStoreApi, useResolvedStoreWithSelector, useResolvedValue, useScheduledBlocker, useUIBlockingContext, useUIBlockingStore, useUIBlockingStoreFromContext };
|