@okyrychenko-dev/react-action-guard 0.5.0 → 0.6.1
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 +147 -17
- package/dist/index.cjs +301 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1206 -62
- package/dist/index.d.ts +1206 -62
- package/dist/index.js +302 -58
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -154,10 +154,12 @@ Gets detailed information about all active blockers for a specific scope.
|
|
|
154
154
|
**BlockerInfo:**
|
|
155
155
|
|
|
156
156
|
- `id: string` - Unique identifier of the blocker
|
|
157
|
-
- `reason
|
|
158
|
-
- `priority: number` - Priority level (0
|
|
157
|
+
- `reason: string` - Reason for blocking (defaults to "Unknown")
|
|
158
|
+
- `priority: number` - Priority level (higher = higher priority, minimum value is 0)
|
|
159
159
|
- `scope: string | string[]` - Scope(s) being blocked
|
|
160
|
-
- `timestamp: number` - When the blocker was added
|
|
160
|
+
- `timestamp: number` - When the blocker was added (milliseconds since epoch)
|
|
161
|
+
- `timeout?: number` - Optional timeout duration in milliseconds
|
|
162
|
+
- `onTimeout?: (blockerId: string) => void` - Optional callback when timeout expires
|
|
161
163
|
|
|
162
164
|
**Example:**
|
|
163
165
|
|
|
@@ -433,22 +435,30 @@ Direct access to the Zustand store for advanced use cases (requires a selector).
|
|
|
433
435
|
**Methods:**
|
|
434
436
|
|
|
435
437
|
- `addBlocker(id, config)` - Manually add a blocker (re-adding with the same ID replaces config)
|
|
438
|
+
- `updateBlocker(id, config)` - Update blocker metadata (timeout restarts if new `timeout` value provided)
|
|
436
439
|
- `removeBlocker(id)` - Manually remove a blocker
|
|
437
440
|
- `isBlocked(scope)` - Check if scope is blocked
|
|
438
441
|
- `getBlockingInfo(scope)` - Get detailed blocking information
|
|
439
|
-
- `clearAllBlockers()` - Remove all blockers
|
|
440
|
-
- `clearBlockersForScope(scope)` - Remove blockers for specific scope
|
|
442
|
+
- `clearAllBlockers()` - Remove all blockers (emits `"clear"` middleware event)
|
|
443
|
+
- `clearBlockersForScope(scope)` - Remove blockers for specific scope (emits `"clear_scope"` middleware event)
|
|
441
444
|
- `registerMiddleware(name, middleware)` - Register middleware manually
|
|
442
445
|
- `unregisterMiddleware(name)` - Unregister middleware manually
|
|
443
446
|
|
|
447
|
+
**Note about `updateBlocker` and timeouts:**
|
|
448
|
+
- If you pass a **new** `timeout` value, the timer will be **restarted**
|
|
449
|
+
- If you **don't** pass `timeout`, the existing timer continues unchanged
|
|
450
|
+
- Set `timeout: 0` to **clear** an existing timeout
|
|
451
|
+
- `addBlocker` always resets/creates a new timeout timer when called with the same ID
|
|
452
|
+
|
|
444
453
|
**Example:**
|
|
445
454
|
|
|
446
455
|
```jsx
|
|
447
456
|
import { useUIBlockingStore } from "@okyrychenko-dev/react-action-guard";
|
|
448
457
|
|
|
449
458
|
function AdvancedComponent() {
|
|
450
|
-
const { addBlocker, removeBlocker } = useUIBlockingStore((state) => ({
|
|
459
|
+
const { addBlocker, updateBlocker, removeBlocker } = useUIBlockingStore((state) => ({
|
|
451
460
|
addBlocker: state.addBlocker,
|
|
461
|
+
updateBlocker: state.updateBlocker,
|
|
452
462
|
removeBlocker: state.removeBlocker,
|
|
453
463
|
}));
|
|
454
464
|
|
|
@@ -461,12 +471,13 @@ function AdvancedComponent() {
|
|
|
461
471
|
};
|
|
462
472
|
|
|
463
473
|
const updatePriority = () => {
|
|
464
|
-
//
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
474
|
+
// Update metadata - timeout continues if not changed
|
|
475
|
+
updateBlocker("custom-blocker", { priority: 200 });
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
const extendTimeout = () => {
|
|
479
|
+
// Update timeout - timer restarts with new value
|
|
480
|
+
updateBlocker("custom-blocker", { timeout: 60000 });
|
|
470
481
|
};
|
|
471
482
|
|
|
472
483
|
const stopBlocking = () => {
|
|
@@ -507,6 +518,30 @@ Advanced store helpers are re-exported from the internal toolkit for custom setu
|
|
|
507
518
|
|
|
508
519
|
The library includes a powerful middleware system that allows you to hook into blocker lifecycle events for analytics, logging, and performance monitoring.
|
|
509
520
|
|
|
521
|
+
### Middleware Actions
|
|
522
|
+
|
|
523
|
+
Middleware receives events for the following actions:
|
|
524
|
+
|
|
525
|
+
- `"add"` - Blocker was added
|
|
526
|
+
- `"update"` - Blocker metadata was updated
|
|
527
|
+
- `"remove"` - Blocker was removed
|
|
528
|
+
- `"timeout"` - Blocker was auto-removed due to timeout
|
|
529
|
+
- `"clear"` - All blockers were cleared (includes `count` field)
|
|
530
|
+
- `"clear_scope"` - Blockers for specific scope were cleared (includes `scope` and `count` fields)
|
|
531
|
+
|
|
532
|
+
**MiddlewareContext type:**
|
|
533
|
+
```typescript
|
|
534
|
+
{
|
|
535
|
+
action: "add" | "update" | "remove" | "timeout" | "clear" | "clear_scope";
|
|
536
|
+
blockerId: string;
|
|
537
|
+
config?: BlockerConfig;
|
|
538
|
+
timestamp: number;
|
|
539
|
+
prevState?: BlockerConfig; // Available for "update" and "remove"
|
|
540
|
+
scope?: string; // Available for "clear_scope"
|
|
541
|
+
count?: number; // Available for "clear" and "clear_scope"
|
|
542
|
+
}
|
|
543
|
+
```
|
|
544
|
+
|
|
510
545
|
### Built-in Middleware
|
|
511
546
|
|
|
512
547
|
#### Analytics Middleware
|
|
@@ -570,8 +605,6 @@ configureMiddleware([
|
|
|
570
605
|
|
|
571
606
|
Note: `configureMiddleware` registers middleware on the global store. If you use `UIBlockingProvider`, register middleware via the provider's `middlewares` prop instead.
|
|
572
607
|
|
|
573
|
-
Note: Middleware action types include `update` and `cancel`, but the store currently emits `add`, `remove`, and `timeout`.
|
|
574
|
-
|
|
575
608
|
### Custom Middleware
|
|
576
609
|
|
|
577
610
|
Create your own middleware to handle blocker events:
|
|
@@ -580,14 +613,20 @@ Create your own middleware to handle blocker events:
|
|
|
580
613
|
import { configureMiddleware } from "@okyrychenko-dev/react-action-guard";
|
|
581
614
|
|
|
582
615
|
const myCustomMiddleware = (context) => {
|
|
583
|
-
const { action, blockerId, config, timestamp } = context;
|
|
616
|
+
const { action, blockerId, config, timestamp, scope, count } = context;
|
|
584
617
|
|
|
585
618
|
if (action === "add") {
|
|
586
619
|
console.log(`Blocker added: ${blockerId}`, config);
|
|
587
|
-
} else if (action === "remove") {
|
|
588
|
-
console.log(`Blocker removed: ${blockerId}`);
|
|
589
620
|
} else if (action === "update") {
|
|
590
621
|
console.log(`Blocker updated: ${blockerId}`, config);
|
|
622
|
+
} else if (action === "remove") {
|
|
623
|
+
console.log(`Blocker removed: ${blockerId}`);
|
|
624
|
+
} else if (action === "timeout") {
|
|
625
|
+
console.log(`Blocker timed out: ${blockerId}`);
|
|
626
|
+
} else if (action === "clear") {
|
|
627
|
+
console.log(`All blockers cleared (${count} total)`);
|
|
628
|
+
} else if (action === "clear_scope") {
|
|
629
|
+
console.log(`Cleared ${count} blocker(s) for scope: ${scope}`);
|
|
591
630
|
}
|
|
592
631
|
};
|
|
593
632
|
|
|
@@ -887,6 +926,97 @@ function StorageQuotaGuard() {
|
|
|
887
926
|
}
|
|
888
927
|
```
|
|
889
928
|
|
|
929
|
+
### Clearing Blockers on Navigation
|
|
930
|
+
|
|
931
|
+
Clear blockers when navigating away or on specific events:
|
|
932
|
+
|
|
933
|
+
```jsx
|
|
934
|
+
import { useUIBlockingStore } from "@okyrychenko-dev/react-action-guard";
|
|
935
|
+
import { useEffect } from "react";
|
|
936
|
+
|
|
937
|
+
function CheckoutPage() {
|
|
938
|
+
const { clearBlockersForScope, clearAllBlockers } = useUIBlockingStore(
|
|
939
|
+
(state) => ({
|
|
940
|
+
clearBlockersForScope: state.clearBlockersForScope,
|
|
941
|
+
clearAllBlockers: state.clearAllBlockers,
|
|
942
|
+
})
|
|
943
|
+
);
|
|
944
|
+
|
|
945
|
+
// Clear checkout-specific blockers when leaving the page
|
|
946
|
+
useEffect(() => {
|
|
947
|
+
return () => {
|
|
948
|
+
// Clean up checkout blockers on unmount
|
|
949
|
+
clearBlockersForScope("checkout");
|
|
950
|
+
};
|
|
951
|
+
}, [clearBlockersForScope]);
|
|
952
|
+
|
|
953
|
+
const handleCancelOrder = () => {
|
|
954
|
+
// Clear all blockers when user explicitly cancels
|
|
955
|
+
clearAllBlockers();
|
|
956
|
+
navigate("/");
|
|
957
|
+
};
|
|
958
|
+
|
|
959
|
+
return (
|
|
960
|
+
<div>
|
|
961
|
+
<CheckoutForm />
|
|
962
|
+
<button onClick={handleCancelOrder}>Cancel Order</button>
|
|
963
|
+
</div>
|
|
964
|
+
);
|
|
965
|
+
}
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
### Managing Session Timeouts with Dynamic Updates
|
|
969
|
+
|
|
970
|
+
Extend or update blocker timeouts dynamically:
|
|
971
|
+
|
|
972
|
+
```jsx
|
|
973
|
+
import { useUIBlockingStore } from "@okyrychenko-dev/react-action-guard";
|
|
974
|
+
|
|
975
|
+
function SessionManager() {
|
|
976
|
+
const { addBlocker, updateBlocker, removeBlocker } = useUIBlockingStore(
|
|
977
|
+
(state) => ({
|
|
978
|
+
addBlocker: state.addBlocker,
|
|
979
|
+
updateBlocker: state.updateBlocker,
|
|
980
|
+
removeBlocker: state.removeBlocker,
|
|
981
|
+
})
|
|
982
|
+
);
|
|
983
|
+
|
|
984
|
+
const startSession = () => {
|
|
985
|
+
addBlocker("session-timeout", {
|
|
986
|
+
scope: "global",
|
|
987
|
+
reason: "Session expiring soon",
|
|
988
|
+
priority: 50,
|
|
989
|
+
timeout: 300000, // 5 minutes
|
|
990
|
+
onTimeout: () => {
|
|
991
|
+
logout();
|
|
992
|
+
showNotification("Session expired");
|
|
993
|
+
},
|
|
994
|
+
});
|
|
995
|
+
};
|
|
996
|
+
|
|
997
|
+
const extendSession = () => {
|
|
998
|
+
// Extend timeout - timer restarts with new value
|
|
999
|
+
updateBlocker("session-timeout", {
|
|
1000
|
+
timeout: 600000, // 10 minutes
|
|
1001
|
+
reason: "Session extended",
|
|
1002
|
+
});
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
const endSession = () => {
|
|
1006
|
+
removeBlocker("session-timeout");
|
|
1007
|
+
logout();
|
|
1008
|
+
};
|
|
1009
|
+
|
|
1010
|
+
return (
|
|
1011
|
+
<div>
|
|
1012
|
+
<button onClick={startSession}>Start Session</button>
|
|
1013
|
+
<button onClick={extendSession}>Extend Session</button>
|
|
1014
|
+
<button onClick={endSession}>Logout</button>
|
|
1015
|
+
</div>
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
```
|
|
1019
|
+
|
|
890
1020
|
## Development
|
|
891
1021
|
|
|
892
1022
|
```bash
|