1
1
import { isArray } from 'lodash' ;
2
- import { useEffect } from 'react' ;
3
-
4
- import { useForceUpdate } from '@react-devui/hooks' ;
2
+ import { useSyncExternalStore } from 'react' ;
5
3
6
4
export type Control = string | number ;
7
5
export type ControlMode = 'one' | 'all' ;
8
- export interface ACLConfig {
9
- full ?: boolean ;
10
- controls ?: Control [ ] ;
11
- }
12
6
13
7
export class ACL {
14
- public controlMode : ControlMode = 'one' ;
8
+ private _full = false ;
9
+ private _controls = new Set < Control > ( ) ;
15
10
16
- private _updates = new Set < ( ) => void > ( ) ;
17
- private _update ( ) {
18
- for ( const cb of this . _updates ) {
19
- cb ( ) ;
20
- }
21
- }
22
- public addUpdateListener ( cb : ( ) => void ) {
23
- this . _updates . add ( cb ) ;
24
- return ( ) => {
25
- this . _updates . delete ( cb ) ;
26
- } ;
27
- }
28
-
29
- private _full : boolean ;
30
11
public get full ( ) : boolean {
31
12
return this . _full ;
32
13
}
33
- public setFull ( full : boolean ) {
34
- this . _full = full ;
35
- this . _update ( ) ;
36
- }
37
14
38
- private _controls : Set < Control > ;
39
15
public get controls ( ) : Control [ ] {
40
16
return Array . from ( this . _controls ) ;
41
17
}
18
+
19
+ public setFull ( full : boolean ) {
20
+ this . _full = full ;
21
+ emitChange ( ) ;
22
+ }
23
+
42
24
public set ( control : Control [ ] ) : void {
43
25
this . _controls = new Set ( control ) ;
44
- this . _update ( ) ;
26
+ emitChange ( ) ;
45
27
}
28
+
46
29
public add ( control : Control | Control [ ] ) : void {
47
30
for ( const v of isArray ( control ) ? control : [ control ] ) {
48
31
this . _controls . add ( v ) ;
49
32
}
50
- this . _update ( ) ;
33
+ emitChange ( ) ;
51
34
}
35
+
52
36
public remove ( control : Control | Control [ ] ) : void {
53
37
for ( const v of isArray ( control ) ? control : [ control ] ) {
54
38
this . _controls . delete ( v ) ;
55
39
}
56
- this . _update ( ) ;
40
+ emitChange ( ) ;
57
41
}
58
42
59
- public can ( control : Control | Control [ ] , mode = this . controlMode ) : boolean {
43
+ public can ( control : Control | Control [ ] , mode : ControlMode = 'one' ) : boolean {
60
44
if ( this . _full ) {
61
45
return true ;
62
46
}
@@ -75,21 +59,29 @@ export class ACL {
75
59
}
76
60
return false ;
77
61
}
78
-
79
- constructor ( config ?: ACLConfig ) {
80
- this . _full = config ?. full ?? false ;
81
- this . _controls = new Set ( config ?. controls ?? [ ] ) ;
82
- }
83
62
}
84
63
85
64
const acl = new ACL ( ) ;
86
65
87
- export function useACL ( ) {
88
- const forceUpdate = useForceUpdate ( ) ;
66
+ let listeners : ( ( ) => void ) [ ] = [ ] ;
89
67
90
- useEffect ( ( ) => {
91
- return acl . addUpdateListener ( forceUpdate ) ;
92
- } , [ forceUpdate ] ) ;
68
+ function subscribe ( onStoreChange : ( ) => void ) {
69
+ listeners = listeners . concat ( [ onStoreChange ] ) ;
70
+ return ( ) => {
71
+ listeners = listeners . filter ( ( f ) => f !== onStoreChange ) ;
72
+ } ;
73
+ }
93
74
75
+ function getSnapshot ( ) {
94
76
return acl ;
95
77
}
78
+
79
+ function emitChange ( ) {
80
+ for ( const listener of listeners ) {
81
+ listener ( ) ;
82
+ }
83
+ }
84
+
85
+ export function useACL ( ) {
86
+ return useSyncExternalStore ( subscribe , getSnapshot ) ;
87
+ }
0 commit comments