@okyrychenko-dev/react-action-guard 0.6.1 → 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 +23 -13
- package/dist/index.cjs +179 -132
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +446 -411
- package/dist/index.d.ts +446 -411
- package/dist/index.js +174 -130
- package/dist/index.js.map +1 -1
- package/package.json +12 -11
package/dist/index.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { useRef, useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
1
|
import { createStoreProvider, createShallowStore } from '@okyrychenko-dev/react-zustand-toolkit';
|
|
3
|
-
export { createShallowStore } from '@okyrychenko-dev/react-zustand-toolkit';
|
|
4
2
|
import { useStore } from 'zustand';
|
|
5
3
|
import 'zustand/react/shallow';
|
|
6
4
|
import { jsx } from 'react/jsx-runtime';
|
|
7
5
|
import { useShallow } from 'zustand/shallow';
|
|
8
6
|
import { devtools } from 'zustand/middleware';
|
|
7
|
+
import { useRef, useCallback, useEffect, useMemo, useState } from 'react';
|
|
9
8
|
|
|
10
|
-
// src/
|
|
9
|
+
// src/context/UIBlockingContext.tsx
|
|
11
10
|
|
|
12
11
|
// src/store/uiBlockingStore.constants.ts
|
|
13
12
|
var DEFAULT_SCOPE = "global";
|
|
@@ -23,16 +22,18 @@ function normalizeScopeToArray(scope) {
|
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
// src/store/uiBlockingStore.actions.ts
|
|
26
|
-
|
|
25
|
+
function normalizePriority(priority, fallback = DEFAULT_PRIORITY) {
|
|
27
26
|
return priority !== void 0 ? Math.max(0, priority) : fallback;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
27
|
+
}
|
|
28
|
+
function createMiddlewareContext(action, blockerId, config, prevState) {
|
|
29
|
+
return {
|
|
30
|
+
action,
|
|
31
|
+
blockerId,
|
|
32
|
+
config,
|
|
33
|
+
timestamp: Date.now(),
|
|
34
|
+
...prevState && { prevState }
|
|
35
|
+
};
|
|
36
|
+
}
|
|
36
37
|
var createUIBlockingActions = (set, get) => ({
|
|
37
38
|
// State
|
|
38
39
|
activeBlockers: /* @__PURE__ */ new Map(),
|
|
@@ -53,25 +54,24 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
53
54
|
},
|
|
54
55
|
runMiddlewares: async (context) => {
|
|
55
56
|
const { middlewares } = get();
|
|
56
|
-
for (const [
|
|
57
|
+
for (const [, middleware] of middlewares) {
|
|
57
58
|
try {
|
|
58
59
|
await middleware(context);
|
|
59
|
-
} catch
|
|
60
|
-
console.error(`[UIBlocking] Middleware "${name}" error:`, error);
|
|
60
|
+
} catch {
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
64
|
// Actions
|
|
65
65
|
/**
|
|
66
66
|
* Adds a new blocker or overwrites an existing one.
|
|
67
|
-
*
|
|
67
|
+
*
|
|
68
68
|
* If a blocker with the same ID already exists, it will be replaced and any
|
|
69
69
|
* existing timeout will be cleared. The blocker is active immediately after
|
|
70
70
|
* being added. Triggers middleware with 'add' action.
|
|
71
|
-
*
|
|
71
|
+
*
|
|
72
72
|
* @param id - Unique identifier for the blocker. Must be unique within the store.
|
|
73
73
|
* @param config - Blocker configuration. All fields are optional with defaults applied.
|
|
74
|
-
*
|
|
74
|
+
*
|
|
75
75
|
* @example
|
|
76
76
|
* Basic usage
|
|
77
77
|
* ```ts
|
|
@@ -81,7 +81,7 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
81
81
|
* priority: 70
|
|
82
82
|
* });
|
|
83
83
|
* ```
|
|
84
|
-
*
|
|
84
|
+
*
|
|
85
85
|
* @example
|
|
86
86
|
* With timeout
|
|
87
87
|
* ```ts
|
|
@@ -92,7 +92,7 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
92
92
|
* onTimeout: (id) => console.warn(`${id} timed out`)
|
|
93
93
|
* });
|
|
94
94
|
* ```
|
|
95
|
-
*
|
|
95
|
+
*
|
|
96
96
|
* @see {@link removeBlocker} to remove a blocker
|
|
97
97
|
* @see {@link updateBlocker} to update an existing blocker
|
|
98
98
|
*/
|
|
@@ -143,13 +143,13 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
143
143
|
},
|
|
144
144
|
/**
|
|
145
145
|
* Updates an existing blocker or creates it if it doesn't exist.
|
|
146
|
-
*
|
|
146
|
+
*
|
|
147
147
|
* Merges the provided configuration with existing blocker data. If the timeout
|
|
148
148
|
* is changed, the timeout timer is restarted. Triggers middleware with 'update' action.
|
|
149
|
-
*
|
|
149
|
+
*
|
|
150
150
|
* @param id - Identifier of the blocker to update
|
|
151
151
|
* @param config - Partial configuration to merge with existing blocker data
|
|
152
|
-
*
|
|
152
|
+
*
|
|
153
153
|
* @example
|
|
154
154
|
* Update blocker reason
|
|
155
155
|
* ```ts
|
|
@@ -157,7 +157,7 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
157
157
|
* reason: 'Saving additional data...'
|
|
158
158
|
* });
|
|
159
159
|
* ```
|
|
160
|
-
*
|
|
160
|
+
*
|
|
161
161
|
* @example
|
|
162
162
|
* Extend timeout
|
|
163
163
|
* ```ts
|
|
@@ -165,7 +165,7 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
165
165
|
* timeout: 60000 // Extend to 60 seconds
|
|
166
166
|
* });
|
|
167
167
|
* ```
|
|
168
|
-
*
|
|
168
|
+
*
|
|
169
169
|
* @see {@link addBlocker} to create a new blocker
|
|
170
170
|
*/
|
|
171
171
|
updateBlocker: (id, config = {}) => {
|
|
@@ -241,12 +241,12 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
241
241
|
},
|
|
242
242
|
/**
|
|
243
243
|
* Removes a blocker from the store.
|
|
244
|
-
*
|
|
244
|
+
*
|
|
245
245
|
* Clears any associated timeout and triggers middleware with 'remove' action.
|
|
246
246
|
* Safe to call even if the blocker doesn't exist (no-op in that case).
|
|
247
|
-
*
|
|
247
|
+
*
|
|
248
248
|
* @param id - Identifier of the blocker to remove
|
|
249
|
-
*
|
|
249
|
+
*
|
|
250
250
|
* @example
|
|
251
251
|
* ```ts
|
|
252
252
|
* // Add and remove a blocker
|
|
@@ -254,7 +254,7 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
254
254
|
* // ... later
|
|
255
255
|
* store.getState().removeBlocker('temp');
|
|
256
256
|
* ```
|
|
257
|
-
*
|
|
257
|
+
*
|
|
258
258
|
* @see {@link addBlocker} to add a blocker
|
|
259
259
|
* @see {@link clearAllBlockers} to remove all blockers at once
|
|
260
260
|
*/
|
|
@@ -274,28 +274,28 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
274
274
|
},
|
|
275
275
|
/**
|
|
276
276
|
* Checks if one or more scopes are currently blocked.
|
|
277
|
-
*
|
|
277
|
+
*
|
|
278
278
|
* Returns true if ANY blocker affects the specified scope(s). Global scope
|
|
279
279
|
* blockers will cause this to return true for any scope check.
|
|
280
|
-
*
|
|
280
|
+
*
|
|
281
281
|
* @param scope - Scope(s) to check. Defaults to "global" if not specified.
|
|
282
282
|
* Can be a single scope string or array of scopes.
|
|
283
283
|
* @returns true if any of the specified scopes are currently blocked
|
|
284
|
-
*
|
|
284
|
+
*
|
|
285
285
|
* @example
|
|
286
286
|
* Single scope check
|
|
287
287
|
* ```ts
|
|
288
288
|
* const isFormBlocked = store.getState().isBlocked('form');
|
|
289
289
|
* console.log(isFormBlocked); // true or false
|
|
290
290
|
* ```
|
|
291
|
-
*
|
|
291
|
+
*
|
|
292
292
|
* @example
|
|
293
293
|
* Multiple scopes check
|
|
294
294
|
* ```ts
|
|
295
295
|
* const isBlocked = store.getState().isBlocked(['form', 'navigation']);
|
|
296
296
|
* // Returns true if either 'form' OR 'navigation' has active blockers
|
|
297
297
|
* ```
|
|
298
|
-
*
|
|
298
|
+
*
|
|
299
299
|
* @see {@link getBlockingInfo} for detailed blocker information
|
|
300
300
|
*/
|
|
301
301
|
isBlocked: (scope = DEFAULT_SCOPE) => {
|
|
@@ -314,14 +314,14 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
314
314
|
},
|
|
315
315
|
/**
|
|
316
316
|
* Gets detailed information about all blockers affecting a specific scope.
|
|
317
|
-
*
|
|
317
|
+
*
|
|
318
318
|
* Returns an array of blocker objects sorted by priority (highest first).
|
|
319
319
|
* Includes global blockers and scope-specific blockers. Each blocker object
|
|
320
320
|
* contains id, reason, priority, scope, timestamp, and timeout information.
|
|
321
|
-
*
|
|
321
|
+
*
|
|
322
322
|
* @param scope - Scope to get blocking information for
|
|
323
323
|
* @returns Array of {@link BlockerInfo} objects, sorted by priority descending
|
|
324
|
-
*
|
|
324
|
+
*
|
|
325
325
|
* @example
|
|
326
326
|
* Display blocker details
|
|
327
327
|
* ```ts
|
|
@@ -331,7 +331,7 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
331
331
|
* console.log(`Priority: ${blocker.priority}`);
|
|
332
332
|
* });
|
|
333
333
|
* ```
|
|
334
|
-
*
|
|
334
|
+
*
|
|
335
335
|
* @example
|
|
336
336
|
* Get highest priority blocker
|
|
337
337
|
* ```ts
|
|
@@ -341,7 +341,7 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
341
341
|
* console.log(`Top blocker: ${topBlocker.reason}`);
|
|
342
342
|
* }
|
|
343
343
|
* ```
|
|
344
|
-
*
|
|
344
|
+
*
|
|
345
345
|
* @see {@link isBlocked} for a simple boolean check
|
|
346
346
|
* @see {@link BlockerInfo} for the structure of returned objects
|
|
347
347
|
*/
|
|
@@ -351,23 +351,24 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
351
351
|
for (const [id, blocker] of activeBlockers) {
|
|
352
352
|
const blockerScopes = normalizeScopeToArray(blocker.scope);
|
|
353
353
|
if (blocker.scope === DEFAULT_SCOPE || blockerScopes.includes(scope)) {
|
|
354
|
-
|
|
354
|
+
const { timeoutId: _timeoutId, ...publicBlocker } = blocker;
|
|
355
|
+
blockers.push({ id, ...publicBlocker });
|
|
355
356
|
}
|
|
356
357
|
}
|
|
357
358
|
return blockers.sort((a, b) => b.priority - a.priority);
|
|
358
359
|
},
|
|
359
360
|
/**
|
|
360
361
|
* Removes all active blockers from the store.
|
|
361
|
-
*
|
|
362
|
+
*
|
|
362
363
|
* Clears all timeouts and triggers middleware with 'clear' action.
|
|
363
364
|
* Useful for resetting the blocking state.
|
|
364
|
-
*
|
|
365
|
+
*
|
|
365
366
|
* @example
|
|
366
367
|
* ```ts
|
|
367
368
|
* // Clear all blockers on logout
|
|
368
369
|
* store.getState().clearAllBlockers();
|
|
369
370
|
* ```
|
|
370
|
-
*
|
|
371
|
+
*
|
|
371
372
|
* @see {@link clearBlockersForScope} to clear blockers for a specific scope
|
|
372
373
|
*/
|
|
373
374
|
clearAllBlockers: () => {
|
|
@@ -390,26 +391,26 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
390
391
|
},
|
|
391
392
|
/**
|
|
392
393
|
* Removes all blockers that affect a specific scope.
|
|
393
|
-
*
|
|
394
|
+
*
|
|
394
395
|
* Clears timeouts for removed blockers and triggers middleware with
|
|
395
396
|
* 'clear_scope' action. Global scope blockers are NOT cleared by this method.
|
|
396
|
-
*
|
|
397
|
+
*
|
|
397
398
|
* @param scope - Scope to clear blockers for
|
|
398
|
-
*
|
|
399
|
+
*
|
|
399
400
|
* @example
|
|
400
401
|
* Clear form blockers
|
|
401
402
|
* ```ts
|
|
402
403
|
* // Clear all blockers affecting 'form' scope
|
|
403
404
|
* store.getState().clearBlockersForScope('form');
|
|
404
405
|
* ```
|
|
405
|
-
*
|
|
406
|
+
*
|
|
406
407
|
* @example
|
|
407
408
|
* Clear on navigation
|
|
408
409
|
* ```ts
|
|
409
410
|
* // Clear navigation blockers when user navigates away
|
|
410
411
|
* store.getState().clearBlockersForScope('navigation');
|
|
411
412
|
* ```
|
|
412
|
-
*
|
|
413
|
+
*
|
|
413
414
|
* @see {@link clearAllBlockers} to clear all blockers
|
|
414
415
|
*/
|
|
415
416
|
clearBlockersForScope: (scope) => {
|
|
@@ -447,18 +448,24 @@ var createUIBlockingActions = (set, get) => ({
|
|
|
447
448
|
});
|
|
448
449
|
var {
|
|
449
450
|
Provider: BaseUIBlockingProvider,
|
|
450
|
-
|
|
451
|
-
useContextStore:
|
|
451
|
+
useContextStoreApi: useUIBlockingContext,
|
|
452
|
+
useContextStore: baseUseUIBlockingStoreFromContext,
|
|
452
453
|
useIsInsideProvider: useIsInsideUIBlockingProvider,
|
|
453
|
-
|
|
454
|
+
useContextStoreOptional: useOptionalUIBlockingContext
|
|
454
455
|
} = createStoreProvider(createUIBlockingActions, "UIBlocking");
|
|
456
|
+
function useUIBlockingStoreFromContext(selector, equalityFn) {
|
|
457
|
+
if (selector) {
|
|
458
|
+
return baseUseUIBlockingStoreFromContext(selector, equalityFn);
|
|
459
|
+
}
|
|
460
|
+
return baseUseUIBlockingStoreFromContext();
|
|
461
|
+
}
|
|
455
462
|
function UIBlockingProvider({
|
|
456
463
|
children,
|
|
457
464
|
enableDevtools = process.env.NODE_ENV === "development",
|
|
458
465
|
devtoolsName = "UIBlocking",
|
|
459
466
|
middlewares = []
|
|
460
467
|
}) {
|
|
461
|
-
const
|
|
468
|
+
const handleStoreInit = (store) => {
|
|
462
469
|
middlewares.forEach((mw, index) => {
|
|
463
470
|
store.getState().registerMiddleware(`provider-middleware-${index.toString()}`, mw);
|
|
464
471
|
});
|
|
@@ -468,7 +475,7 @@ function UIBlockingProvider({
|
|
|
468
475
|
{
|
|
469
476
|
enableDevtools,
|
|
470
477
|
devtoolsName,
|
|
471
|
-
|
|
478
|
+
onStoreInit: handleStoreInit,
|
|
472
479
|
children
|
|
473
480
|
}
|
|
474
481
|
);
|
|
@@ -481,24 +488,31 @@ var devtoolsConfig = {
|
|
|
481
488
|
};
|
|
482
489
|
|
|
483
490
|
// src/store/uiBlockingStore.store.ts
|
|
484
|
-
var
|
|
491
|
+
var storeBindings = createShallowStore(
|
|
492
|
+
devtools(createUIBlockingActions, devtoolsConfig)
|
|
493
|
+
);
|
|
494
|
+
var uiBlockingStoreApi = storeBindings.useStoreApi;
|
|
495
|
+
function useUIBlockingStore(selector, equalityFn) {
|
|
496
|
+
if (selector) {
|
|
497
|
+
return storeBindings.useStore(selector, equalityFn);
|
|
498
|
+
}
|
|
499
|
+
return storeBindings.useStore();
|
|
500
|
+
}
|
|
485
501
|
|
|
486
502
|
// src/context/useResolvedStore.ts
|
|
487
503
|
function useOptionalContextStore() {
|
|
488
|
-
return
|
|
504
|
+
return useOptionalUIBlockingContext();
|
|
489
505
|
}
|
|
490
|
-
function
|
|
506
|
+
function useResolvedStoreApi() {
|
|
491
507
|
const contextStore = useOptionalContextStore();
|
|
492
508
|
return contextStore ?? uiBlockingStoreApi;
|
|
493
509
|
}
|
|
494
|
-
function
|
|
495
|
-
const store =
|
|
510
|
+
function useResolvedValue(selector) {
|
|
511
|
+
const store = useResolvedStoreApi();
|
|
496
512
|
return useStore(store, useShallow(selector));
|
|
497
513
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
var useAsyncAction = (actionId, scope, options) => {
|
|
501
|
-
const { addBlocker, removeBlocker } = useResolvedStoreWithSelector((state) => ({
|
|
514
|
+
function useAsyncAction(actionId, scope, options) {
|
|
515
|
+
const { addBlocker, removeBlocker } = useResolvedValue((state) => ({
|
|
502
516
|
addBlocker: state.addBlocker,
|
|
503
517
|
removeBlocker: state.removeBlocker
|
|
504
518
|
}));
|
|
@@ -523,22 +537,36 @@ var useAsyncAction = (actionId, scope, options) => {
|
|
|
523
537
|
[actionId, scope, options?.timeout, options?.onTimeout, addBlocker, removeBlocker]
|
|
524
538
|
);
|
|
525
539
|
return executeWithBlocking;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
const { addBlocker, removeBlocker } =
|
|
540
|
+
}
|
|
541
|
+
function useBlocker(blockerId, config, isActive = true) {
|
|
542
|
+
const { addBlocker, removeBlocker, updateBlocker } = useResolvedValue((state) => ({
|
|
529
543
|
addBlocker: state.addBlocker,
|
|
530
|
-
removeBlocker: state.removeBlocker
|
|
544
|
+
removeBlocker: state.removeBlocker,
|
|
545
|
+
updateBlocker: state.updateBlocker
|
|
531
546
|
}));
|
|
547
|
+
const lastConfigRef = useRef(null);
|
|
532
548
|
useEffect(() => {
|
|
533
549
|
if (!isActive || !blockerId) {
|
|
534
550
|
return;
|
|
535
551
|
}
|
|
536
552
|
addBlocker(blockerId, config);
|
|
553
|
+
lastConfigRef.current = config;
|
|
537
554
|
return () => {
|
|
555
|
+
lastConfigRef.current = null;
|
|
538
556
|
removeBlocker(blockerId);
|
|
539
557
|
};
|
|
540
558
|
}, [blockerId, isActive, addBlocker, removeBlocker]);
|
|
541
|
-
|
|
559
|
+
useEffect(() => {
|
|
560
|
+
if (!isActive || !blockerId) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
if (lastConfigRef.current === config) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
updateBlocker(blockerId, config);
|
|
567
|
+
lastConfigRef.current = config;
|
|
568
|
+
}, [blockerId, config, isActive, updateBlocker]);
|
|
569
|
+
}
|
|
542
570
|
|
|
543
571
|
// src/hooks/useBlocker/useBlocker.utils.ts
|
|
544
572
|
function createBlockerConfig(config) {
|
|
@@ -548,13 +576,13 @@ function createBlockerConfig(config) {
|
|
|
548
576
|
priority: config.priority
|
|
549
577
|
};
|
|
550
578
|
}
|
|
551
|
-
|
|
552
|
-
const store =
|
|
579
|
+
function useBlockingInfo(scope = DEFAULT_SCOPE) {
|
|
580
|
+
const store = useResolvedStoreApi();
|
|
553
581
|
const activeBlockers = useStore(store, (state) => state.activeBlockers);
|
|
554
582
|
return useMemo(() => {
|
|
555
583
|
return store.getState().getBlockingInfo(scope);
|
|
556
584
|
}, [activeBlockers, scope, store]);
|
|
557
|
-
}
|
|
585
|
+
}
|
|
558
586
|
function useConfigRef(config) {
|
|
559
587
|
const configRef = useRef(config);
|
|
560
588
|
useEffect(() => {
|
|
@@ -564,8 +592,8 @@ function useConfigRef(config) {
|
|
|
564
592
|
}
|
|
565
593
|
|
|
566
594
|
// src/hooks/useConditionalBlocker/useConditionalBlocker.ts
|
|
567
|
-
|
|
568
|
-
const { addBlocker, removeBlocker } =
|
|
595
|
+
function useConditionalBlocker(blockerId, config) {
|
|
596
|
+
const { addBlocker, removeBlocker } = useResolvedValue((state) => ({
|
|
569
597
|
addBlocker: state.addBlocker,
|
|
570
598
|
removeBlocker: state.removeBlocker
|
|
571
599
|
}));
|
|
@@ -600,8 +628,8 @@ var useConditionalBlocker = (blockerId, config) => {
|
|
|
600
628
|
}
|
|
601
629
|
};
|
|
602
630
|
}, [checkCondition, blockerId, removeBlocker]);
|
|
603
|
-
}
|
|
604
|
-
|
|
631
|
+
}
|
|
632
|
+
function useConfirmableBlocker(blockerId, config) {
|
|
605
633
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
606
634
|
const [isExecuting, setIsExecuting] = useState(false);
|
|
607
635
|
useBlocker(
|
|
@@ -620,9 +648,6 @@ var useConfirmableBlocker = (blockerId, config) => {
|
|
|
620
648
|
setIsExecuting(true);
|
|
621
649
|
try {
|
|
622
650
|
await config.onConfirm();
|
|
623
|
-
} catch (error) {
|
|
624
|
-
console.error("[UIBlocking] Confirmable action error:", error);
|
|
625
|
-
throw error;
|
|
626
651
|
} finally {
|
|
627
652
|
setIsExecuting(false);
|
|
628
653
|
}
|
|
@@ -644,12 +669,12 @@ var useConfirmableBlocker = (blockerId, config) => {
|
|
|
644
669
|
onConfirm,
|
|
645
670
|
onCancel
|
|
646
671
|
};
|
|
647
|
-
}
|
|
672
|
+
}
|
|
648
673
|
|
|
649
674
|
// src/hooks/useIsBlocked/useIsBlocked.ts
|
|
650
|
-
|
|
651
|
-
return
|
|
652
|
-
}
|
|
675
|
+
function useIsBlocked(scope) {
|
|
676
|
+
return useResolvedValue((state) => state.isBlocked(scope));
|
|
677
|
+
}
|
|
653
678
|
|
|
654
679
|
// src/hooks/useScheduledBlocker/useScheduledBlocker.utils.ts
|
|
655
680
|
var MAX_TIMEOUT_MS = 2147483647;
|
|
@@ -689,8 +714,8 @@ function isScheduleInPast(startTime, endTime, now) {
|
|
|
689
714
|
}
|
|
690
715
|
|
|
691
716
|
// src/hooks/useScheduledBlocker/useScheduledBlocker.ts
|
|
692
|
-
|
|
693
|
-
const { addBlocker, removeBlocker } =
|
|
717
|
+
function useScheduledBlocker(blockerId, config) {
|
|
718
|
+
const { addBlocker, removeBlocker } = useResolvedValue((state) => ({
|
|
694
719
|
addBlocker: state.addBlocker,
|
|
695
720
|
removeBlocker: state.removeBlocker
|
|
696
721
|
}));
|
|
@@ -711,7 +736,6 @@ var useScheduledBlocker = (blockerId, config) => {
|
|
|
711
736
|
const startTime = parseDate(currentConfig.schedule.start);
|
|
712
737
|
const now = Date.now();
|
|
713
738
|
if (!isValidTimestamp(startTime)) {
|
|
714
|
-
console.error(`[UIBlocking] Invalid start time for blocker "${blockerId}"`);
|
|
715
739
|
return;
|
|
716
740
|
}
|
|
717
741
|
const scheduleEnd = () => {
|
|
@@ -736,9 +760,6 @@ var useScheduledBlocker = (blockerId, config) => {
|
|
|
736
760
|
if (startTime > now) {
|
|
737
761
|
const delay = startTime - now;
|
|
738
762
|
if (!isSafeTimeout(delay)) {
|
|
739
|
-
console.warn(
|
|
740
|
-
`[UIBlocking] Schedule delay exceeds maximum timeout (${MAX_TIMEOUT_MS.toString()}ms) for blocker "${blockerId}"`
|
|
741
|
-
);
|
|
742
763
|
return;
|
|
743
764
|
}
|
|
744
765
|
timeoutsRef.current.start = setTimeout(startBlocking, delay);
|
|
@@ -747,7 +768,7 @@ var useScheduledBlocker = (blockerId, config) => {
|
|
|
747
768
|
if (isInBlockingPeriod(startTime, endTime, now)) {
|
|
748
769
|
startBlocking();
|
|
749
770
|
} else if (isScheduleInPast(startTime, endTime, now)) {
|
|
750
|
-
|
|
771
|
+
return;
|
|
751
772
|
}
|
|
752
773
|
}
|
|
753
774
|
return () => {
|
|
@@ -755,13 +776,19 @@ var useScheduledBlocker = (blockerId, config) => {
|
|
|
755
776
|
removeBlocker(blockerId);
|
|
756
777
|
};
|
|
757
778
|
}, [blockerId, addBlocker, removeBlocker, cleanup]);
|
|
758
|
-
}
|
|
779
|
+
}
|
|
759
780
|
|
|
760
781
|
// src/middleware/analyticsMiddleware.utils.ts
|
|
761
|
-
|
|
782
|
+
function capitalizeFirst(str) {
|
|
762
783
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
763
|
-
}
|
|
764
|
-
|
|
784
|
+
}
|
|
785
|
+
function getAnalyticsWindow() {
|
|
786
|
+
if (typeof window === "undefined") {
|
|
787
|
+
return void 0;
|
|
788
|
+
}
|
|
789
|
+
return window;
|
|
790
|
+
}
|
|
791
|
+
function buildEventData(context) {
|
|
765
792
|
const eventData = {
|
|
766
793
|
blocker_id: context.blockerId
|
|
767
794
|
};
|
|
@@ -776,33 +803,36 @@ var buildEventData = (context) => {
|
|
|
776
803
|
eventData.priority = priority;
|
|
777
804
|
}
|
|
778
805
|
return eventData;
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
806
|
+
}
|
|
807
|
+
function trackGoogleAnalytics(action, eventData) {
|
|
808
|
+
const analyticsWindow = getAnalyticsWindow();
|
|
809
|
+
if (analyticsWindow?.gtag) {
|
|
810
|
+
analyticsWindow.gtag("event", `ui_blocking_${action}`, eventData);
|
|
783
811
|
}
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
|
|
812
|
+
}
|
|
813
|
+
function trackMixpanel(action, eventData) {
|
|
814
|
+
const analyticsWindow = getAnalyticsWindow();
|
|
815
|
+
if (analyticsWindow?.mixpanel) {
|
|
787
816
|
const eventName = `UI Blocking ${action.split("_").map(capitalizeFirst).join(" ")}`;
|
|
788
|
-
|
|
817
|
+
analyticsWindow.mixpanel.track(eventName, eventData);
|
|
789
818
|
}
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
|
|
819
|
+
}
|
|
820
|
+
function trackAmplitude(action, eventData) {
|
|
821
|
+
const analyticsWindow = getAnalyticsWindow();
|
|
822
|
+
if (analyticsWindow?.amplitude) {
|
|
793
823
|
const eventName = `UI Blocking ${action.split("_").map(capitalizeFirst).join(" ")}`;
|
|
794
|
-
|
|
824
|
+
analyticsWindow.amplitude.track(eventName, eventData);
|
|
795
825
|
}
|
|
796
|
-
}
|
|
797
|
-
|
|
826
|
+
}
|
|
827
|
+
function trackCustom(trackFn, action, eventData) {
|
|
798
828
|
try {
|
|
799
829
|
trackFn(`ui_blocking_${action}`, eventData);
|
|
800
830
|
} catch {
|
|
801
831
|
}
|
|
802
|
-
}
|
|
832
|
+
}
|
|
803
833
|
|
|
804
834
|
// src/middleware/analyticsMiddleware.ts
|
|
805
|
-
|
|
835
|
+
function trackEvent(config, context, eventData) {
|
|
806
836
|
if ("provider" in config) {
|
|
807
837
|
switch (config.provider) {
|
|
808
838
|
case "ga":
|
|
@@ -819,25 +849,31 @@ var trackEvent = (config, context, eventData) => {
|
|
|
819
849
|
if ("track" in config) {
|
|
820
850
|
trackCustom(config.track, context.action, eventData);
|
|
821
851
|
}
|
|
822
|
-
}
|
|
823
|
-
|
|
852
|
+
}
|
|
853
|
+
function createAnalyticsMiddleware(config) {
|
|
824
854
|
return (context) => {
|
|
825
855
|
const eventData = buildEventData(context);
|
|
826
856
|
trackEvent(config, context, eventData);
|
|
827
857
|
};
|
|
828
|
-
}
|
|
858
|
+
}
|
|
829
859
|
|
|
830
860
|
// src/middleware/configureMiddleware.ts
|
|
861
|
+
var CONFIGURE_MIDDLEWARE_PREFIX = "middleware-";
|
|
831
862
|
function configureMiddleware(middlewares) {
|
|
832
863
|
const store = uiBlockingStoreApi.getState();
|
|
864
|
+
store.middlewares.forEach((_, name) => {
|
|
865
|
+
if (name.startsWith(CONFIGURE_MIDDLEWARE_PREFIX)) {
|
|
866
|
+
store.unregisterMiddleware(name);
|
|
867
|
+
}
|
|
868
|
+
});
|
|
833
869
|
middlewares.forEach((middleware, index) => {
|
|
834
|
-
const name =
|
|
870
|
+
const name = `${CONFIGURE_MIDDLEWARE_PREFIX}${index.toString()}`;
|
|
835
871
|
store.registerMiddleware(name, middleware);
|
|
836
872
|
});
|
|
837
873
|
}
|
|
838
874
|
|
|
839
875
|
// src/middleware/loggerMiddleware.utils.ts
|
|
840
|
-
|
|
876
|
+
function getActionEmoji(action) {
|
|
841
877
|
switch (action) {
|
|
842
878
|
case "add":
|
|
843
879
|
return "\u2795";
|
|
@@ -854,8 +890,8 @@ var getActionEmoji = (action) => {
|
|
|
854
890
|
default:
|
|
855
891
|
return "\u2753";
|
|
856
892
|
}
|
|
857
|
-
}
|
|
858
|
-
|
|
893
|
+
}
|
|
894
|
+
function extractConfigDetails(config) {
|
|
859
895
|
if (!config) {
|
|
860
896
|
return {};
|
|
861
897
|
}
|
|
@@ -868,8 +904,8 @@ var extractConfigDetails = (config) => {
|
|
|
868
904
|
details.priority = priority;
|
|
869
905
|
}
|
|
870
906
|
return details;
|
|
871
|
-
}
|
|
872
|
-
|
|
907
|
+
}
|
|
908
|
+
function formatLogData(context) {
|
|
873
909
|
const configDetails = extractConfigDetails(context.config);
|
|
874
910
|
const logData = {};
|
|
875
911
|
if (context.scope !== void 0) {
|
|
@@ -888,26 +924,26 @@ var formatLogData = (context) => {
|
|
|
888
924
|
return configDetails;
|
|
889
925
|
}
|
|
890
926
|
return Object.keys(logData).length === 1 && logData.config ? configDetails : logData;
|
|
891
|
-
}
|
|
927
|
+
}
|
|
892
928
|
|
|
893
929
|
// src/middleware/loggerMiddleware.ts
|
|
894
930
|
var LOG_PREFIX = "[UIBlocking]";
|
|
895
|
-
|
|
931
|
+
function loggerMiddleware(context) {
|
|
896
932
|
const emoji = getActionEmoji(context.action);
|
|
897
933
|
const logData = formatLogData(context);
|
|
898
934
|
console.log(LOG_PREFIX, emoji, context.blockerId, logData);
|
|
899
|
-
}
|
|
935
|
+
}
|
|
900
936
|
|
|
901
937
|
// src/middleware/performanceMiddleware.utils.ts
|
|
902
|
-
|
|
938
|
+
function handleAddAction(blockerId, timestamp, blockStartTimes) {
|
|
903
939
|
blockStartTimes.set(blockerId, timestamp);
|
|
904
|
-
}
|
|
940
|
+
}
|
|
905
941
|
|
|
906
942
|
// src/middleware/performanceMiddleware.ts
|
|
907
943
|
var DEFAULT_SLOW_BLOCK_THRESHOLD = 3e3;
|
|
908
944
|
var ACTION_ADD = "add";
|
|
909
945
|
var ACTION_REMOVE = "remove";
|
|
910
|
-
|
|
946
|
+
function handleRemoveAction(context, blockStartTimes, slowBlockThreshold, onSlowBlock) {
|
|
911
947
|
const startTime = blockStartTimes.get(context.blockerId);
|
|
912
948
|
if (startTime === void 0) {
|
|
913
949
|
return;
|
|
@@ -915,13 +951,10 @@ var handleRemoveAction = (context, blockStartTimes, slowBlockThreshold, onSlowBl
|
|
|
915
951
|
const duration = context.timestamp - startTime;
|
|
916
952
|
blockStartTimes.delete(context.blockerId);
|
|
917
953
|
if (duration >= slowBlockThreshold) {
|
|
918
|
-
console.warn(
|
|
919
|
-
`[UIBlocking] Slow block detected: "${context.blockerId}" took ${duration.toString()}ms`
|
|
920
|
-
);
|
|
921
954
|
onSlowBlock?.(context.blockerId, duration);
|
|
922
955
|
}
|
|
923
|
-
}
|
|
924
|
-
|
|
956
|
+
}
|
|
957
|
+
function createPerformanceMiddleware(config = {}) {
|
|
925
958
|
const { slowBlockThreshold = DEFAULT_SLOW_BLOCK_THRESHOLD, onSlowBlock } = config;
|
|
926
959
|
const blockStartTimes = /* @__PURE__ */ new Map();
|
|
927
960
|
return (context) => {
|
|
@@ -931,7 +964,7 @@ var createPerformanceMiddleware = (config = {}) => {
|
|
|
931
964
|
handleRemoveAction(context, blockStartTimes, slowBlockThreshold, onSlowBlock);
|
|
932
965
|
}
|
|
933
966
|
};
|
|
934
|
-
}
|
|
967
|
+
}
|
|
935
968
|
|
|
936
969
|
// src/createTypedHooks.ts
|
|
937
970
|
function createTypedHooks() {
|
|
@@ -949,6 +982,17 @@ function createTypedHooks() {
|
|
|
949
982
|
};
|
|
950
983
|
}
|
|
951
984
|
|
|
952
|
-
|
|
985
|
+
// src/index.ts
|
|
986
|
+
function useOptionalContext() {
|
|
987
|
+
return useOptionalUIBlockingContext();
|
|
988
|
+
}
|
|
989
|
+
function useResolvedStore() {
|
|
990
|
+
return useResolvedStoreApi();
|
|
991
|
+
}
|
|
992
|
+
function useResolvedStoreWithSelector(selector) {
|
|
993
|
+
return useResolvedValue(selector);
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
export { UIBlockingProvider, configureMiddleware, createAnalyticsMiddleware, createPerformanceMiddleware, createTypedHooks, loggerMiddleware, uiBlockingStoreApi, useAsyncAction, useBlocker, useBlockingInfo, useConditionalBlocker, useConfirmableBlocker, useIsBlocked, useIsInsideUIBlockingProvider, useOptionalContext, useOptionalUIBlockingContext, useResolvedStore, useResolvedStoreApi, useResolvedStoreWithSelector, useResolvedValue, useScheduledBlocker, useUIBlockingContext, useUIBlockingStore, useUIBlockingStoreFromContext };
|
|
953
997
|
//# sourceMappingURL=index.js.map
|
|
954
998
|
//# sourceMappingURL=index.js.map
|