@blac/core 2.0.0-rc-1 → 2.0.0-rc-3
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 +53 -45
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +10 -101
- package/dist/index.es.js +217 -316
- package/dist/index.es.js.map +1 -1
- package/package.json +1 -1
- package/src/Blac.ts +41 -108
- package/src/BlacObserver.ts +17 -12
- package/src/BlocBase.ts +14 -33
- package/src/index.ts +2 -3
- package/src/types.ts +1 -1
- package/src/BlacObservable.ts +0 -85
- package/src/BlacPlugin.ts +0 -13
- package/src/addons/BlacAddon.ts +0 -17
- package/src/addons/Persist.ts +0 -105
- package/src/addons/index.ts +0 -1
package/src/BlocBase.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import { Blac
|
|
1
|
+
import { Blac } from './Blac';
|
|
2
2
|
import { BlacObservable } from './BlacObserver';
|
|
3
|
-
import BlacAddon from './addons/BlacAddon';
|
|
4
3
|
import { BlocConstructor } from './types';
|
|
5
4
|
|
|
6
5
|
export type BlocInstanceId = string | number | undefined;
|
|
7
|
-
type DependencySelector<S> = (newState: S
|
|
6
|
+
type DependencySelector<S> = (newState: S) => unknown[][];
|
|
8
7
|
|
|
9
8
|
// Define an interface for the static properties expected on a Bloc/Cubit constructor
|
|
10
9
|
interface BlocStaticProperties {
|
|
11
10
|
isolated: boolean;
|
|
12
11
|
keepAlive: boolean;
|
|
13
|
-
addons?: BlacAddon[];
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
/**
|
|
@@ -25,6 +23,7 @@ export abstract class BlocBase<
|
|
|
25
23
|
S,
|
|
26
24
|
P = unknown
|
|
27
25
|
> {
|
|
26
|
+
public uid = crypto.randomUUID();
|
|
28
27
|
/**
|
|
29
28
|
* When true, every consumer will receive its own unique instance of this Bloc.
|
|
30
29
|
* Use this when state should not be shared between components.
|
|
@@ -50,12 +49,6 @@ export abstract class BlocBase<
|
|
|
50
49
|
* When provided, observers will only be notified when selected dependencies change.
|
|
51
50
|
*/
|
|
52
51
|
defaultDependencySelector: DependencySelector<S> | undefined;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* @internal
|
|
56
|
-
* Optional array of addons to extend the functionality of this Bloc.
|
|
57
|
-
*/
|
|
58
|
-
public _addons?: BlacAddon[];
|
|
59
52
|
|
|
60
53
|
/**
|
|
61
54
|
* @internal
|
|
@@ -126,7 +119,7 @@ export abstract class BlocBase<
|
|
|
126
119
|
constructor(initialState: S) {
|
|
127
120
|
this._state = initialState;
|
|
128
121
|
this._observer = new BlacObservable(this);
|
|
129
|
-
|
|
122
|
+
Blac.log('Bloc Created', this)
|
|
130
123
|
this._id = this.constructor.name;
|
|
131
124
|
|
|
132
125
|
// Use a type assertion for the constructor to access static properties safely
|
|
@@ -134,9 +127,6 @@ export abstract class BlocBase<
|
|
|
134
127
|
|
|
135
128
|
this._keepAlive = constructorWithStaticProps.keepAlive;
|
|
136
129
|
this._isolated = constructorWithStaticProps.isolated;
|
|
137
|
-
this._addons = constructorWithStaticProps.addons;
|
|
138
|
-
|
|
139
|
-
this._connectAddons();
|
|
140
130
|
}
|
|
141
131
|
|
|
142
132
|
/**
|
|
@@ -174,9 +164,11 @@ export abstract class BlocBase<
|
|
|
174
164
|
* Notifies the Blac manager and clears all observers.
|
|
175
165
|
*/
|
|
176
166
|
_dispose() {
|
|
177
|
-
this._observer.
|
|
178
|
-
this._blac.dispatchEvent(BlacLifecycleEvent.BLOC_DISPOSED, this);
|
|
167
|
+
this._observer.clear();
|
|
179
168
|
this.onDispose?.();
|
|
169
|
+
// this._blac.dispatchEvent(BlacLifecycleEvent.BLOC_DISPOSED, this);
|
|
170
|
+
Blac.log('BlocBase._dispose', this);
|
|
171
|
+
Blac.instance.disposeBloc(this);
|
|
180
172
|
}
|
|
181
173
|
|
|
182
174
|
/**
|
|
@@ -199,8 +191,10 @@ export abstract class BlocBase<
|
|
|
199
191
|
* @param consumerId The unique ID of the consumer being added
|
|
200
192
|
*/
|
|
201
193
|
_addConsumer = (consumerId: string) => {
|
|
194
|
+
if (this._consumers.has(consumerId)) return;
|
|
202
195
|
this._consumers.add(consumerId);
|
|
203
|
-
this._blac.dispatchEvent(BlacLifecycleEvent.BLOC_CONSUMER_ADDED, this, { consumerId });
|
|
196
|
+
// this._blac.dispatchEvent(BlacLifecycleEvent.BLOC_CONSUMER_ADDED, this, { consumerId });
|
|
197
|
+
Blac.log('BlocBase._addConsumer', this, consumerId);
|
|
204
198
|
};
|
|
205
199
|
|
|
206
200
|
/**
|
|
@@ -211,23 +205,10 @@ export abstract class BlocBase<
|
|
|
211
205
|
* @param consumerId The unique ID of the consumer being removed
|
|
212
206
|
*/
|
|
213
207
|
_removeConsumer = (consumerId: string) => {
|
|
214
|
-
this.
|
|
208
|
+
if (!this._consumers.has(consumerId)) return;
|
|
215
209
|
this._consumers.delete(consumerId);
|
|
216
|
-
this._blac.dispatchEvent(BlacLifecycleEvent.BLOC_CONSUMER_REMOVED, this, { consumerId });
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* @internal
|
|
221
|
-
* Initializes all registered addons for this Bloc instance.
|
|
222
|
-
* Calls the onInit lifecycle method on each addon if defined.
|
|
223
|
-
*/
|
|
224
|
-
_connectAddons = () => {
|
|
225
|
-
const { _addons: addons } = this;
|
|
226
|
-
if (addons) {
|
|
227
|
-
addons.forEach(addon => {
|
|
228
|
-
addon.onInit?.(this);
|
|
229
|
-
});
|
|
230
|
-
}
|
|
210
|
+
// this._blac.dispatchEvent(BlacLifecycleEvent.BLOC_CONSUMER_REMOVED, this, { consumerId });
|
|
211
|
+
Blac.log('BlocBase._removeConsumer', this, consumerId);
|
|
231
212
|
};
|
|
232
213
|
|
|
233
214
|
lastUpdate = Date.now();
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED
package/src/BlacObservable.ts
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { Blac, BlacLifecycleEvent } from './Blac';
|
|
2
|
-
import { BlocBase } from './BlocBase';
|
|
3
|
-
import { BlocHookDependencyArrayFn } from './types';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Represents an observer that can subscribe to state changes in a Bloc
|
|
7
|
-
* @template S - The type of state being observed
|
|
8
|
-
*/
|
|
9
|
-
export type BlacObserver<S> = {
|
|
10
|
-
/** Function to be called when state changes */
|
|
11
|
-
fn: (newState: S, oldState: S, action?: unknown) => void | Promise<void>;
|
|
12
|
-
/** Optional function to determine if the observer should be notified of state changes */
|
|
13
|
-
dependencyArray?: BlocHookDependencyArrayFn<S>;
|
|
14
|
-
/** Cached state values used for dependency comparison */
|
|
15
|
-
lastState?: unknown[][];
|
|
16
|
-
/** Unique identifier for the observer */
|
|
17
|
-
id: string;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* A class that manages observers for a Bloc's state changes
|
|
22
|
-
* @template S - The type of state being observed
|
|
23
|
-
*/
|
|
24
|
-
export class BlacObservable<S = unknown> {
|
|
25
|
-
/** The Bloc instance this observable is associated with */
|
|
26
|
-
bloc: BlocBase<S>;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Creates a new BlacObservable instance
|
|
30
|
-
* @param bloc - The Bloc instance to observe
|
|
31
|
-
*/
|
|
32
|
-
constructor(bloc: BlocBase<S>) {
|
|
33
|
-
this.bloc = bloc;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
private _observers = new Set<BlacObserver<S>>();
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Gets the number of active observers
|
|
40
|
-
* @returns The number of observers currently subscribed
|
|
41
|
-
*/
|
|
42
|
-
get size(): number {
|
|
43
|
-
return this._observers.size;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Gets the set of all observers
|
|
48
|
-
* @returns The Set of all BlacObserver instances
|
|
49
|
-
*/
|
|
50
|
-
get observers() {
|
|
51
|
-
return this._observers;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Subscribes an observer to state changes
|
|
56
|
-
* @param observer - The observer to subscribe
|
|
57
|
-
* @returns A function that can be called to unsubscribe the observer
|
|
58
|
-
*/
|
|
59
|
-
subscribe(observer: BlacObserver<S>): () => void {
|
|
60
|
-
this._observers.add(observer);
|
|
61
|
-
Blac.instance.dispatchEvent(BlacLifecycleEvent.LISTENER_ADDED, this.bloc, { listenerId: observer.id });
|
|
62
|
-
|
|
63
|
-
// Immediately notify the new observer with the current state
|
|
64
|
-
// Pass current state as both newState and oldState for initial notification context
|
|
65
|
-
void observer.fn(this.bloc.state, this.bloc.state, { initialSubscription: true });
|
|
66
|
-
|
|
67
|
-
if (!observer.lastState) {
|
|
68
|
-
observer.lastState = observer.dependencyArray
|
|
69
|
-
? observer.dependencyArray(this.bloc.state)
|
|
70
|
-
: [];
|
|
71
|
-
}
|
|
72
|
-
return () => {
|
|
73
|
-
this.unsubscribe(observer);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Unsubscribes an observer from state changes
|
|
79
|
-
* @param observer - The observer to unsubscribe
|
|
80
|
-
*/
|
|
81
|
-
unsubscribe(observer: BlacObserver<S>) {
|
|
82
|
-
this._observers.delete(observer);
|
|
83
|
-
Blac.instance.dispatchEvent(BlacLifecycleEvent.LISTENER_REMOVED, this.bloc, { listenerId: observer.id });
|
|
84
|
-
}
|
|
85
|
-
}
|
package/src/BlacPlugin.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { BlacLifecycleEvent } from './Blac';
|
|
2
|
-
import { BlocBase } from './BlocBase';
|
|
3
|
-
|
|
4
|
-
export interface BlacPlugin {
|
|
5
|
-
name: string;
|
|
6
|
-
|
|
7
|
-
onEvent(
|
|
8
|
-
event: BlacLifecycleEvent,
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
-
bloc: BlocBase<any>,
|
|
11
|
-
params?: unknown,
|
|
12
|
-
): void;
|
|
13
|
-
}
|
package/src/addons/BlacAddon.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { BlocBase } from '../BlocBase';
|
|
2
|
-
|
|
3
|
-
export type BlacAddonInit = (bloc: BlocBase<any>) => void;
|
|
4
|
-
|
|
5
|
-
export type BlacAddonEmit = (params: {
|
|
6
|
-
oldState: unknown;
|
|
7
|
-
newState: unknown;
|
|
8
|
-
cubit: BlocBase<any>;
|
|
9
|
-
}) => void;
|
|
10
|
-
|
|
11
|
-
type BlacAddon = {
|
|
12
|
-
name: string;
|
|
13
|
-
onInit?: BlacAddonInit;
|
|
14
|
-
onEmit?: BlacAddonEmit;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export default BlacAddon;
|
package/src/addons/Persist.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { BlocBase, BlocInstanceId } from '../BlocBase';
|
|
2
|
-
import BlacAddon, { BlacAddonEmit, BlacAddonInit } from './BlacAddon';
|
|
3
|
-
|
|
4
|
-
type StorageType = 'localStorage' | 'sessionStorage';
|
|
5
|
-
|
|
6
|
-
function getStorage(type: StorageType): Storage {
|
|
7
|
-
switch (type) {
|
|
8
|
-
case 'localStorage':
|
|
9
|
-
return localStorage;
|
|
10
|
-
case 'sessionStorage':
|
|
11
|
-
return sessionStorage;
|
|
12
|
-
default:
|
|
13
|
-
return localStorage;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Persist addon
|
|
19
|
-
*
|
|
20
|
-
* @param options
|
|
21
|
-
* @returns BlacAddon
|
|
22
|
-
*/
|
|
23
|
-
export function Persist(
|
|
24
|
-
options: {
|
|
25
|
-
/**
|
|
26
|
-
* @default 'blac'
|
|
27
|
-
*/
|
|
28
|
-
keyPrefix?: string;
|
|
29
|
-
/**
|
|
30
|
-
* @default the bloc's id
|
|
31
|
-
*/
|
|
32
|
-
keyName?: string;
|
|
33
|
-
/**
|
|
34
|
-
* Used when the value is not found in storage
|
|
35
|
-
*/
|
|
36
|
-
defaultValue?: unknown;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @default 'localStorage'
|
|
40
|
-
* @see StorageType
|
|
41
|
-
*/
|
|
42
|
-
storageType?: StorageType;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* @default false
|
|
46
|
-
*/
|
|
47
|
-
onError?: (e: unknown) => void;
|
|
48
|
-
} = {},
|
|
49
|
-
): BlacAddon {
|
|
50
|
-
const {
|
|
51
|
-
keyPrefix = 'blac',
|
|
52
|
-
keyName,
|
|
53
|
-
defaultValue,
|
|
54
|
-
storageType = 'localStorage',
|
|
55
|
-
} = options;
|
|
56
|
-
|
|
57
|
-
const fullKey = (id: string | BlocInstanceId) => `${keyPrefix}:${String(id)}`;
|
|
58
|
-
|
|
59
|
-
const getFromLocalStorage = (id: string | BlocInstanceId): unknown => {
|
|
60
|
-
try {
|
|
61
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
62
|
-
const value = getStorage(storageType).getItem(fullKey(id));
|
|
63
|
-
if (typeof value !== 'string') {
|
|
64
|
-
return defaultValue;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const p = JSON.parse(value) as { v: unknown };
|
|
68
|
-
if (typeof p.v !== 'undefined') {
|
|
69
|
-
return p.v;
|
|
70
|
-
} else {
|
|
71
|
-
return defaultValue;
|
|
72
|
-
}
|
|
73
|
-
} catch (e) {
|
|
74
|
-
options.onError?.(e);
|
|
75
|
-
return defaultValue;
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
80
|
-
const onInit: BlacAddonInit = (e: BlocBase<any>) => {
|
|
81
|
-
const id = keyName ?? e._id;
|
|
82
|
-
|
|
83
|
-
const value = getFromLocalStorage(id);
|
|
84
|
-
e._pushState(value, null);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
let currentCachedValue = '';
|
|
88
|
-
const onEmit: BlacAddonEmit = ({ newState, cubit }) => {
|
|
89
|
-
const id = keyName ?? cubit._id;
|
|
90
|
-
|
|
91
|
-
const newValue = JSON.stringify({ v: newState });
|
|
92
|
-
|
|
93
|
-
if (newValue !== currentCachedValue) {
|
|
94
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
95
|
-
getStorage(storageType).setItem(fullKey(id), newValue);
|
|
96
|
-
currentCachedValue = newValue;
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
return {
|
|
101
|
-
name: 'Persist',
|
|
102
|
-
onInit,
|
|
103
|
-
onEmit,
|
|
104
|
-
};
|
|
105
|
-
}
|
package/src/addons/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './Persist';
|