@okyrychenko-dev/react-action-guard 0.3.3 → 0.4.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/LICENSE +1 -1
- package/README.md +120 -10
- package/dist/index.cjs +132 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +172 -2
- package/dist/index.d.ts +172 -2
- package/dist/index.js +129 -16
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,32 @@
|
|
|
1
1
|
import * as zustand from 'zustand';
|
|
2
|
+
import { StoreApi } from 'zustand';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
2
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Options for useAsyncAction hook
|
|
7
|
+
*/
|
|
8
|
+
interface UseAsyncActionOptions {
|
|
9
|
+
/** Timeout in milliseconds after which the blocker will be automatically removed */
|
|
10
|
+
timeout?: number;
|
|
11
|
+
/** Callback invoked when the blocker is automatically removed due to timeout */
|
|
12
|
+
onTimeout?: (blockerId: string) => void;
|
|
13
|
+
}
|
|
3
14
|
/**
|
|
4
15
|
* Hook to wrap async functions with automatic blocking/unblocking
|
|
5
16
|
*
|
|
6
17
|
* Creates a wrapper function that automatically adds a blocker before executing
|
|
7
18
|
* the async function and removes it after completion (success or failure).
|
|
8
19
|
*
|
|
20
|
+
* Supports both global store and context store (via UIBlockingProvider).
|
|
21
|
+
*
|
|
9
22
|
* @template T - The return type of the async function
|
|
10
23
|
* @param actionId - Unique identifier for the action (used in blocker ID and reason)
|
|
11
24
|
* @param scope - Scope(s) to block during execution (default: "global")
|
|
25
|
+
* @param options - Optional configuration including timeout
|
|
12
26
|
* @returns Function that wraps async functions with blocking behavior
|
|
13
27
|
*
|
|
14
28
|
*/
|
|
15
|
-
declare const useAsyncAction: <T = unknown>(actionId: string, scope?: string | ReadonlyArray<string
|
|
29
|
+
declare const useAsyncAction: <T = unknown>(actionId: string, scope?: string | ReadonlyArray<string>, options?: UseAsyncActionOptions) => ((asyncFn: () => Promise<T>) => Promise<T>);
|
|
16
30
|
|
|
17
31
|
type AnalyticsEventData = Record<string, string | number | ReadonlyArray<string> | undefined>;
|
|
18
32
|
type AnalyticsProvider = "ga" | "mixpanel" | "amplitude";
|
|
@@ -71,6 +85,10 @@ interface BlockerConfig {
|
|
|
71
85
|
reason?: string;
|
|
72
86
|
priority?: number;
|
|
73
87
|
timestamp?: number;
|
|
88
|
+
/** Automatically remove the blocker after N milliseconds */
|
|
89
|
+
timeout?: number;
|
|
90
|
+
/** Callback invoked when the blocker is automatically removed due to timeout */
|
|
91
|
+
onTimeout?: (blockerId: string) => void;
|
|
74
92
|
}
|
|
75
93
|
/**
|
|
76
94
|
* Stored blocker with all required fields
|
|
@@ -80,6 +98,12 @@ interface StoredBlocker {
|
|
|
80
98
|
reason: string;
|
|
81
99
|
priority: number;
|
|
82
100
|
timestamp: number;
|
|
101
|
+
/** Timeout duration in milliseconds (if set) */
|
|
102
|
+
timeout?: number;
|
|
103
|
+
/** Internal timeout ID for cleanup */
|
|
104
|
+
timeoutId?: ReturnType<typeof setTimeout>;
|
|
105
|
+
/** Callback invoked when the blocker is automatically removed due to timeout */
|
|
106
|
+
onTimeout?: (blockerId: string) => void;
|
|
83
107
|
}
|
|
84
108
|
/**
|
|
85
109
|
* Blocker information including its ID
|
|
@@ -135,6 +159,8 @@ declare const uiBlockingStoreApi: zustand.StoreApi<UIBlockingStore>;
|
|
|
135
159
|
* Automatically adds a blocker when the component mounts (or when activated)
|
|
136
160
|
* and removes it when the component unmounts (or when deactivated).
|
|
137
161
|
*
|
|
162
|
+
* Supports both global store and context store (via UIBlockingProvider).
|
|
163
|
+
*
|
|
138
164
|
* @param blockerId - Unique identifier for the blocker
|
|
139
165
|
* @param config - Blocker configuration (scope, reason, priority)
|
|
140
166
|
* @param isActive - Whether the blocker is currently active (default: true)
|
|
@@ -151,6 +177,8 @@ declare const useBlocker: (blockerId: string, config: BlockerConfig, isActive?:
|
|
|
151
177
|
* Uses a stable reference - only re-renders when the actual blocker list changes,
|
|
152
178
|
* not on every store update.
|
|
153
179
|
*
|
|
180
|
+
* Supports both global store and context store (via UIBlockingProvider).
|
|
181
|
+
*
|
|
154
182
|
* @param scope - Scope to get blocking information for (default: "global")
|
|
155
183
|
* @returns Array of blocker information objects, sorted by priority
|
|
156
184
|
*
|
|
@@ -181,6 +209,8 @@ interface ConditionalBlockerConfig<TState = unknown> extends Omit<BlockerConfig,
|
|
|
181
209
|
* Periodically checks a condition and blocks/unblocks based on the result.
|
|
182
210
|
* The condition is evaluated at the specified interval (default 1000ms).
|
|
183
211
|
*
|
|
212
|
+
* Supports both global store and context store (via UIBlockingProvider).
|
|
213
|
+
*
|
|
184
214
|
* @param blockerId - Unique identifier for this blocker
|
|
185
215
|
* @param config - Configuration including condition function and check interval
|
|
186
216
|
*
|
|
@@ -240,6 +270,8 @@ declare const useConfirmableBlocker: (blockerId: string, config: ConfirmableBloc
|
|
|
240
270
|
* Returns a boolean indicating whether the specified scope(s) are blocked.
|
|
241
271
|
* Automatically re-renders when the blocking state changes.
|
|
242
272
|
*
|
|
273
|
+
* Supports both global store and context store (via UIBlockingProvider).
|
|
274
|
+
*
|
|
243
275
|
* @param scope - Scope or array of scopes to check (default: "global")
|
|
244
276
|
* @returns True if any of the specified scopes are blocked
|
|
245
277
|
*
|
|
@@ -282,10 +314,148 @@ interface ScheduledBlockerConfig extends BlockerConfig {
|
|
|
282
314
|
* Supports start/end times as Date objects, ISO strings, or timestamps.
|
|
283
315
|
* If both duration and end are provided, duration takes precedence.
|
|
284
316
|
*
|
|
317
|
+
* Supports both global store and context store (via UIBlockingProvider).
|
|
318
|
+
*
|
|
285
319
|
* @param blockerId - Unique identifier for this blocker
|
|
286
320
|
* @param config - Configuration including schedule and callbacks
|
|
287
321
|
*
|
|
288
322
|
*/
|
|
289
323
|
declare const useScheduledBlocker: (blockerId: string, config: ScheduledBlockerConfig) => void;
|
|
290
324
|
|
|
291
|
-
|
|
325
|
+
/**
|
|
326
|
+
* Default scope type
|
|
327
|
+
*/
|
|
328
|
+
type DefaultScopes = "global";
|
|
329
|
+
/**
|
|
330
|
+
* Utility type for scope values - can be a single scope or array of scopes
|
|
331
|
+
*/
|
|
332
|
+
type ScopeValue<TScope extends string = string> = TScope | ReadonlyArray<TScope>;
|
|
333
|
+
/**
|
|
334
|
+
* Type-safe blocker configuration with generic scope type
|
|
335
|
+
*/
|
|
336
|
+
interface BlockerConfigTyped<TScope extends string> {
|
|
337
|
+
/** Scope(s) to block */
|
|
338
|
+
scope?: ScopeValue<TScope>;
|
|
339
|
+
/** Human-readable reason for blocking */
|
|
340
|
+
reason?: string;
|
|
341
|
+
/** Priority level (higher priority blockers take precedence) */
|
|
342
|
+
priority?: number;
|
|
343
|
+
/** Timestamp when the blocker was created */
|
|
344
|
+
timestamp?: number;
|
|
345
|
+
/** Timeout in milliseconds after which the blocker will be automatically removed */
|
|
346
|
+
timeout?: number;
|
|
347
|
+
/** Callback invoked when the blocker is automatically removed due to timeout */
|
|
348
|
+
onTimeout?: (blockerId: string) => void;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Return type for createTypedHooks factory
|
|
353
|
+
*/
|
|
354
|
+
interface TypedHooks<TScope extends string> {
|
|
355
|
+
/**
|
|
356
|
+
* Type-safe version of useBlocker hook
|
|
357
|
+
*/
|
|
358
|
+
useBlocker: (blockerId: string, config: BlockerConfigTyped<TScope>, isActive?: boolean) => void;
|
|
359
|
+
/**
|
|
360
|
+
* Type-safe version of useIsBlocked hook
|
|
361
|
+
*/
|
|
362
|
+
useIsBlocked: (scope?: ScopeValue<TScope>) => boolean;
|
|
363
|
+
/**
|
|
364
|
+
* Type-safe version of useAsyncAction hook
|
|
365
|
+
*/
|
|
366
|
+
useAsyncAction: <T = unknown>(actionId: string, scope?: ScopeValue<TScope>, options?: UseAsyncActionOptions) => (asyncFn: () => Promise<T>) => Promise<T>;
|
|
367
|
+
/**
|
|
368
|
+
* Type-safe version of useBlockingInfo hook
|
|
369
|
+
*/
|
|
370
|
+
useBlockingInfo: (scope: TScope) => ReturnType<typeof useBlockingInfo>;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Creates type-safe versions of all blocking hooks with your custom scope types
|
|
374
|
+
*
|
|
375
|
+
* @template TScope - Union type of allowed scope strings
|
|
376
|
+
* @returns Object with type-safe hook functions
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```typescript
|
|
380
|
+
* // Define your app's scopes
|
|
381
|
+
* type AppScopes = "global" | "form" | "navigation" | "checkout";
|
|
382
|
+
*
|
|
383
|
+
* // Create typed hooks
|
|
384
|
+
* const { useBlocker, useIsBlocked, useAsyncAction } = createTypedHooks<AppScopes>();
|
|
385
|
+
*
|
|
386
|
+
* // Now TypeScript will catch typos
|
|
387
|
+
* useBlocker("id", { scope: "form" }); // ✓ OK
|
|
388
|
+
* useBlocker("id", { scope: "typo" }); // ✗ Type error!
|
|
389
|
+
* ```
|
|
390
|
+
*/
|
|
391
|
+
declare function createTypedHooks<TScope extends string>(): TypedHooks<TScope>;
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Props for UIBlockingProvider component
|
|
395
|
+
*/
|
|
396
|
+
interface UIBlockingProviderProps {
|
|
397
|
+
children: ReactNode;
|
|
398
|
+
/** Enable Redux DevTools integration (default: true in development) */
|
|
399
|
+
enableDevtools?: boolean;
|
|
400
|
+
/** Name for Redux DevTools (default: "UIBlocking") */
|
|
401
|
+
devtoolsName?: string;
|
|
402
|
+
/** Initial middlewares to register */
|
|
403
|
+
middlewares?: ReadonlyArray<Middleware>;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Provider component for isolated UI blocking state
|
|
407
|
+
*
|
|
408
|
+
* Use this to create an isolated store instance for:
|
|
409
|
+
* - Server-side rendering (each request gets its own store)
|
|
410
|
+
* - Testing (no need for beforeEach cleanup)
|
|
411
|
+
* - Micro-frontends (isolated state per app)
|
|
412
|
+
*
|
|
413
|
+
* @example
|
|
414
|
+
* ```tsx
|
|
415
|
+
* // SSR - each request gets its own store
|
|
416
|
+
* function App() {
|
|
417
|
+
* return (
|
|
418
|
+
* <UIBlockingProvider>
|
|
419
|
+
* <MyComponent />
|
|
420
|
+
* </UIBlockingProvider>
|
|
421
|
+
* );
|
|
422
|
+
* }
|
|
423
|
+
*
|
|
424
|
+
* // Testing - isolated store per test
|
|
425
|
+
* function renderWithProvider(ui: ReactElement) {
|
|
426
|
+
* return render(
|
|
427
|
+
* <UIBlockingProvider>{ui}</UIBlockingProvider>
|
|
428
|
+
* );
|
|
429
|
+
* }
|
|
430
|
+
* ```
|
|
431
|
+
*/
|
|
432
|
+
declare function UIBlockingProvider({ children, enableDevtools, devtoolsName, middlewares, }: UIBlockingProviderProps): ReactNode;
|
|
433
|
+
/**
|
|
434
|
+
* Hook to access the UIBlocking store from context
|
|
435
|
+
*
|
|
436
|
+
* Throws an error if used outside of UIBlockingProvider.
|
|
437
|
+
* Use useUIBlockingStoreFromContext for safe access with fallback.
|
|
438
|
+
*
|
|
439
|
+
* @returns The store API from the nearest UIBlockingProvider
|
|
440
|
+
* @throws Error if used outside of UIBlockingProvider
|
|
441
|
+
*/
|
|
442
|
+
declare function useUIBlockingContext(): StoreApi<UIBlockingStore>;
|
|
443
|
+
/**
|
|
444
|
+
* Hook to check if we're inside a UIBlockingProvider
|
|
445
|
+
*
|
|
446
|
+
* @returns true if inside UIBlockingProvider, false otherwise
|
|
447
|
+
*/
|
|
448
|
+
declare function useIsInsideUIBlockingProvider(): boolean;
|
|
449
|
+
/**
|
|
450
|
+
* Hook to use the UIBlocking store from context with a selector
|
|
451
|
+
*
|
|
452
|
+
* This is similar to useUIBlockingStore but uses the context store.
|
|
453
|
+
* Automatically applies shallow comparison to prevent unnecessary re-renders.
|
|
454
|
+
*
|
|
455
|
+
* @param selector - Selector function to pick state from the store
|
|
456
|
+
* @returns Selected state value
|
|
457
|
+
* @throws Error if used outside of UIBlockingProvider
|
|
458
|
+
*/
|
|
459
|
+
declare function useUIBlockingStoreFromContext<T>(selector: (state: UIBlockingStore) => T): T;
|
|
460
|
+
|
|
461
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { devtools } from 'zustand/middleware';
|
|
1
|
+
import { createContext, useRef, useMemo, useContext, useCallback, useEffect, useState } from 'react';
|
|
3
2
|
import { createStore, useStore } from 'zustand';
|
|
3
|
+
import { devtools } from 'zustand/middleware';
|
|
4
4
|
import { useShallow } from 'zustand/shallow';
|
|
5
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
6
|
|
|
6
7
|
// src/hooks/useAsyncAction/useAsyncAction.ts
|
|
7
8
|
|
|
@@ -65,13 +66,40 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
65
66
|
*
|
|
66
67
|
*/
|
|
67
68
|
addBlocker: (id, config = {}) => {
|
|
69
|
+
const existingBlocker = get().activeBlockers.get(id);
|
|
70
|
+
if (existingBlocker?.timeoutId) {
|
|
71
|
+
clearTimeout(existingBlocker.timeoutId);
|
|
72
|
+
}
|
|
73
|
+
let timeoutId;
|
|
74
|
+
if (config.timeout && config.timeout > 0) {
|
|
75
|
+
timeoutId = setTimeout(() => {
|
|
76
|
+
if (get().activeBlockers.has(id)) {
|
|
77
|
+
config.onTimeout?.(id);
|
|
78
|
+
void get().runMiddlewares({
|
|
79
|
+
action: "timeout",
|
|
80
|
+
blockerId: id,
|
|
81
|
+
config: {
|
|
82
|
+
scope: config.scope,
|
|
83
|
+
reason: config.reason,
|
|
84
|
+
priority: config.priority,
|
|
85
|
+
timeout: config.timeout
|
|
86
|
+
},
|
|
87
|
+
timestamp: Date.now()
|
|
88
|
+
});
|
|
89
|
+
get().removeBlocker(id);
|
|
90
|
+
}
|
|
91
|
+
}, config.timeout);
|
|
92
|
+
}
|
|
68
93
|
set((state) => {
|
|
69
94
|
const newBlockers = new Map(state.activeBlockers);
|
|
70
95
|
const storedBlocker = {
|
|
71
96
|
scope: config.scope ?? DEFAULT_SCOPE,
|
|
72
97
|
reason: config.reason ?? DEFAULT_REASON,
|
|
73
98
|
priority: config.priority ?? DEFAULT_PRIORITY,
|
|
74
|
-
timestamp: config.timestamp ?? Date.now()
|
|
99
|
+
timestamp: config.timestamp ?? Date.now(),
|
|
100
|
+
timeout: config.timeout,
|
|
101
|
+
timeoutId,
|
|
102
|
+
onTimeout: config.onTimeout
|
|
75
103
|
};
|
|
76
104
|
newBlockers.set(id, storedBlocker);
|
|
77
105
|
return { activeBlockers: newBlockers };
|
|
@@ -82,7 +110,8 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
82
110
|
config: {
|
|
83
111
|
scope: config.scope,
|
|
84
112
|
reason: config.reason,
|
|
85
|
-
priority: config.priority
|
|
113
|
+
priority: config.priority,
|
|
114
|
+
timeout: config.timeout
|
|
86
115
|
},
|
|
87
116
|
timestamp: Date.now()
|
|
88
117
|
});
|
|
@@ -95,6 +124,9 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
95
124
|
*/
|
|
96
125
|
removeBlocker: (id) => {
|
|
97
126
|
const prevBlocker = get().activeBlockers.get(id);
|
|
127
|
+
if (prevBlocker?.timeoutId) {
|
|
128
|
+
clearTimeout(prevBlocker.timeoutId);
|
|
129
|
+
}
|
|
98
130
|
set((state) => {
|
|
99
131
|
const newBlockers = new Map(state.activeBlockers);
|
|
100
132
|
newBlockers.delete(id);
|
|
@@ -153,6 +185,12 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
153
185
|
* Clear all blockers from the store
|
|
154
186
|
*/
|
|
155
187
|
clearAllBlockers: () => {
|
|
188
|
+
const { activeBlockers } = get();
|
|
189
|
+
for (const [, blocker] of activeBlockers) {
|
|
190
|
+
if (blocker.timeoutId) {
|
|
191
|
+
clearTimeout(blocker.timeoutId);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
156
194
|
set({ activeBlockers: /* @__PURE__ */ new Map() });
|
|
157
195
|
},
|
|
158
196
|
/**
|
|
@@ -162,6 +200,13 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
162
200
|
*
|
|
163
201
|
*/
|
|
164
202
|
clearBlockersForScope: (scope) => {
|
|
203
|
+
const { activeBlockers } = get();
|
|
204
|
+
for (const [, blocker] of activeBlockers) {
|
|
205
|
+
const blockerScopes = normalizeScopeToArray(blocker.scope);
|
|
206
|
+
if (blockerScopes.includes(scope) && blocker.timeoutId) {
|
|
207
|
+
clearTimeout(blocker.timeoutId);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
165
210
|
set((state) => {
|
|
166
211
|
const newBlockers = /* @__PURE__ */ new Map();
|
|
167
212
|
for (const [id, blocker] of state.activeBlockers) {
|
|
@@ -174,6 +219,45 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
174
219
|
});
|
|
175
220
|
}
|
|
176
221
|
});
|
|
222
|
+
var UIBlockingContext = createContext(null);
|
|
223
|
+
function UIBlockingProvider({
|
|
224
|
+
children,
|
|
225
|
+
enableDevtools = process.env.NODE_ENV === "development",
|
|
226
|
+
devtoolsName = "UIBlocking",
|
|
227
|
+
middlewares = []
|
|
228
|
+
}) {
|
|
229
|
+
const middlewaresRef = useRef(middlewares);
|
|
230
|
+
const store = useMemo(() => {
|
|
231
|
+
const baseStore = enableDevtools ? createStore(
|
|
232
|
+
devtools(createUIBlockingActions, {
|
|
233
|
+
name: devtoolsName,
|
|
234
|
+
enabled: enableDevtools
|
|
235
|
+
})
|
|
236
|
+
) : createStore(createUIBlockingActions);
|
|
237
|
+
middlewaresRef.current.forEach((mw, index) => {
|
|
238
|
+
baseStore.getState().registerMiddleware(`provider-middleware-${index.toString()}`, mw);
|
|
239
|
+
});
|
|
240
|
+
return baseStore;
|
|
241
|
+
}, [enableDevtools, devtoolsName]);
|
|
242
|
+
return /* @__PURE__ */ jsx(UIBlockingContext.Provider, { value: store, children });
|
|
243
|
+
}
|
|
244
|
+
function useUIBlockingContext() {
|
|
245
|
+
const store = useContext(UIBlockingContext);
|
|
246
|
+
if (!store) {
|
|
247
|
+
throw new Error(
|
|
248
|
+
"useUIBlockingContext must be used within UIBlockingProvider. Either wrap your app in <UIBlockingProvider> or use the global store via useUIBlockingStore."
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
return store;
|
|
252
|
+
}
|
|
253
|
+
function useIsInsideUIBlockingProvider() {
|
|
254
|
+
const store = useContext(UIBlockingContext);
|
|
255
|
+
return store !== null;
|
|
256
|
+
}
|
|
257
|
+
function useUIBlockingStoreFromContext(selector) {
|
|
258
|
+
const store = useUIBlockingContext();
|
|
259
|
+
return useStore(store, useShallow(selector));
|
|
260
|
+
}
|
|
177
261
|
|
|
178
262
|
// src/store/uiBlockingStore.config.ts
|
|
179
263
|
var devtoolsConfig = {
|
|
@@ -184,9 +268,19 @@ var devtoolsConfig = {
|
|
|
184
268
|
// src/store/uiBlockingStore.store.ts
|
|
185
269
|
var { useStore: useUIBlockingStore, useStoreApi: uiBlockingStoreApi } = createShallowStore(devtools(createUIBlockingActions, devtoolsConfig));
|
|
186
270
|
|
|
271
|
+
// src/context/useResolvedStore.ts
|
|
272
|
+
function useResolvedStore() {
|
|
273
|
+
const contextStore = useContext(UIBlockingContext);
|
|
274
|
+
return contextStore ?? uiBlockingStoreApi;
|
|
275
|
+
}
|
|
276
|
+
function useResolvedStoreWithSelector(selector) {
|
|
277
|
+
const store = useResolvedStore();
|
|
278
|
+
return useStore(store, useShallow(selector));
|
|
279
|
+
}
|
|
280
|
+
|
|
187
281
|
// src/hooks/useAsyncAction/useAsyncAction.ts
|
|
188
|
-
var useAsyncAction = (actionId, scope) => {
|
|
189
|
-
const { addBlocker, removeBlocker } =
|
|
282
|
+
var useAsyncAction = (actionId, scope, options) => {
|
|
283
|
+
const { addBlocker, removeBlocker } = useResolvedStoreWithSelector((state) => ({
|
|
190
284
|
addBlocker: state.addBlocker,
|
|
191
285
|
removeBlocker: state.removeBlocker
|
|
192
286
|
}));
|
|
@@ -197,19 +291,21 @@ var useAsyncAction = (actionId, scope) => {
|
|
|
197
291
|
addBlocker(blockerId, {
|
|
198
292
|
scope,
|
|
199
293
|
reason: `Executing ${actionId}`,
|
|
200
|
-
priority: ASYNC_ACTION_PRIORITY
|
|
294
|
+
priority: ASYNC_ACTION_PRIORITY,
|
|
295
|
+
timeout: options?.timeout,
|
|
296
|
+
onTimeout: options?.onTimeout
|
|
201
297
|
});
|
|
202
298
|
return await asyncFn();
|
|
203
299
|
} finally {
|
|
204
300
|
removeBlocker(blockerId);
|
|
205
301
|
}
|
|
206
302
|
},
|
|
207
|
-
[actionId, scope, addBlocker, removeBlocker]
|
|
303
|
+
[actionId, scope, options?.timeout, options?.onTimeout, addBlocker, removeBlocker]
|
|
208
304
|
);
|
|
209
305
|
return executeWithBlocking;
|
|
210
306
|
};
|
|
211
307
|
var useBlocker = (blockerId, config, isActive = true) => {
|
|
212
|
-
const { addBlocker, removeBlocker } =
|
|
308
|
+
const { addBlocker, removeBlocker } = useResolvedStoreWithSelector((state) => ({
|
|
213
309
|
addBlocker: state.addBlocker,
|
|
214
310
|
removeBlocker: state.removeBlocker
|
|
215
311
|
}));
|
|
@@ -233,10 +329,11 @@ function createBlockerConfig(config) {
|
|
|
233
329
|
};
|
|
234
330
|
}
|
|
235
331
|
var useBlockingInfo = (scope = DEFAULT_SCOPE) => {
|
|
236
|
-
const
|
|
332
|
+
const store = useResolvedStore();
|
|
333
|
+
const activeBlockers = useStore(store, (state) => state.activeBlockers);
|
|
237
334
|
return useMemo(() => {
|
|
238
|
-
return
|
|
239
|
-
}, [activeBlockers, scope]);
|
|
335
|
+
return store.getState().getBlockingInfo(scope);
|
|
336
|
+
}, [activeBlockers, scope, store]);
|
|
240
337
|
};
|
|
241
338
|
function useConfigRef(config) {
|
|
242
339
|
const configRef = useRef(config);
|
|
@@ -248,7 +345,7 @@ function useConfigRef(config) {
|
|
|
248
345
|
|
|
249
346
|
// src/hooks/useConditionalBlocker/useConditionalBlocker.ts
|
|
250
347
|
var useConditionalBlocker = (blockerId, config) => {
|
|
251
|
-
const { addBlocker, removeBlocker } =
|
|
348
|
+
const { addBlocker, removeBlocker } = useResolvedStoreWithSelector((state) => ({
|
|
252
349
|
addBlocker: state.addBlocker,
|
|
253
350
|
removeBlocker: state.removeBlocker
|
|
254
351
|
}));
|
|
@@ -331,7 +428,7 @@ var useConfirmableBlocker = (blockerId, config) => {
|
|
|
331
428
|
|
|
332
429
|
// src/hooks/useIsBlocked/useIsBlocked.ts
|
|
333
430
|
var useIsBlocked = (scope) => {
|
|
334
|
-
return
|
|
431
|
+
return useResolvedStoreWithSelector((state) => state.isBlocked(scope));
|
|
335
432
|
};
|
|
336
433
|
|
|
337
434
|
// src/hooks/useScheduledBlocker/useScheduledBlocker.utils.ts
|
|
@@ -373,7 +470,7 @@ function isScheduleInPast(startTime, endTime, now) {
|
|
|
373
470
|
|
|
374
471
|
// src/hooks/useScheduledBlocker/useScheduledBlocker.ts
|
|
375
472
|
var useScheduledBlocker = (blockerId, config) => {
|
|
376
|
-
const { addBlocker, removeBlocker } =
|
|
473
|
+
const { addBlocker, removeBlocker } = useResolvedStoreWithSelector((state) => ({
|
|
377
474
|
addBlocker: state.addBlocker,
|
|
378
475
|
removeBlocker: state.removeBlocker
|
|
379
476
|
}));
|
|
@@ -604,6 +701,22 @@ var createPerformanceMiddleware = (config = {}) => {
|
|
|
604
701
|
};
|
|
605
702
|
};
|
|
606
703
|
|
|
607
|
-
|
|
704
|
+
// src/createTypedHooks.ts
|
|
705
|
+
function createTypedHooks() {
|
|
706
|
+
return {
|
|
707
|
+
useBlocker: (blockerId, config, isActive) => {
|
|
708
|
+
useBlocker(blockerId, config, isActive);
|
|
709
|
+
},
|
|
710
|
+
useIsBlocked: (scope) => {
|
|
711
|
+
return useIsBlocked(scope);
|
|
712
|
+
},
|
|
713
|
+
useAsyncAction: (actionId, scope, options) => {
|
|
714
|
+
return useAsyncAction(actionId, scope, options);
|
|
715
|
+
},
|
|
716
|
+
useBlockingInfo: (scope) => useBlockingInfo(scope)
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
export { UIBlockingProvider, configureMiddleware, createAnalyticsMiddleware, createPerformanceMiddleware, createTypedHooks, loggerMiddleware, uiBlockingStoreApi, useAsyncAction, useBlocker, useBlockingInfo, useConditionalBlocker, useConfirmableBlocker, useIsBlocked, useIsInsideUIBlockingProvider, useScheduledBlocker, useUIBlockingContext, useUIBlockingStore, useUIBlockingStoreFromContext };
|
|
608
721
|
//# sourceMappingURL=index.js.map
|
|
609
722
|
//# sourceMappingURL=index.js.map
|