11import { isArray } from 'lodash' ;
2- import { useEffect } from 'react' ;
3-
4- import { useForceUpdate } from '@react-devui/hooks' ;
2+ import { useSyncExternalStore } from 'react' ;
53
64export type Control = string | number ;
75export type ControlMode = 'one' | 'all' ;
8- export interface ACLConfig {
9- full ?: boolean ;
10- controls ?: Control [ ] ;
11- }
126
137export class ACL {
14- public controlMode : ControlMode = 'one' ;
8+ private _full = false ;
9+ private _controls = new Set < Control > ( ) ;
1510
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 ;
3011 public get full ( ) : boolean {
3112 return this . _full ;
3213 }
33- public setFull ( full : boolean ) {
34- this . _full = full ;
35- this . _update ( ) ;
36- }
3714
38- private _controls : Set < Control > ;
3915 public get controls ( ) : Control [ ] {
4016 return Array . from ( this . _controls ) ;
4117 }
18+
19+ public setFull ( full : boolean ) {
20+ this . _full = full ;
21+ emitChange ( ) ;
22+ }
23+
4224 public set ( control : Control [ ] ) : void {
4325 this . _controls = new Set ( control ) ;
44- this . _update ( ) ;
26+ emitChange ( ) ;
4527 }
28+
4629 public add ( control : Control | Control [ ] ) : void {
4730 for ( const v of isArray ( control ) ? control : [ control ] ) {
4831 this . _controls . add ( v ) ;
4932 }
50- this . _update ( ) ;
33+ emitChange ( ) ;
5134 }
35+
5236 public remove ( control : Control | Control [ ] ) : void {
5337 for ( const v of isArray ( control ) ? control : [ control ] ) {
5438 this . _controls . delete ( v ) ;
5539 }
56- this . _update ( ) ;
40+ emitChange ( ) ;
5741 }
5842
59- public can ( control : Control | Control [ ] , mode = this . controlMode ) : boolean {
43+ public can ( control : Control | Control [ ] , mode : ControlMode = 'one' ) : boolean {
6044 if ( this . _full ) {
6145 return true ;
6246 }
@@ -75,21 +59,29 @@ export class ACL {
7559 }
7660 return false ;
7761 }
78-
79- constructor ( config ?: ACLConfig ) {
80- this . _full = config ?. full ?? false ;
81- this . _controls = new Set ( config ?. controls ?? [ ] ) ;
82- }
8362}
8463
8564const acl = new ACL ( ) ;
8665
87- export function useACL ( ) {
88- const forceUpdate = useForceUpdate ( ) ;
66+ let listeners : ( ( ) => void ) [ ] = [ ] ;
8967
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+ }
9374
75+ function getSnapshot ( ) {
9476 return acl ;
9577}
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