@figliolia/galena 3.0.2 → 4.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.
Files changed (47) hide show
  1. package/README.md +42 -54
  2. package/dist/API.cjs +9 -0
  3. package/dist/API.d.cts +13 -0
  4. package/dist/API.d.cts.map +1 -0
  5. package/dist/API.d.mts +13 -0
  6. package/dist/API.d.mts.map +1 -0
  7. package/dist/API.mjs +11 -0
  8. package/dist/API.mjs.map +1 -0
  9. package/dist/Galena.cjs +80 -22
  10. package/dist/Galena.d.cts +69 -22
  11. package/dist/Galena.d.cts.map +1 -1
  12. package/dist/Galena.d.mts +69 -22
  13. package/dist/Galena.d.mts.map +1 -1
  14. package/dist/Galena.mjs +80 -22
  15. package/dist/Galena.mjs.map +1 -1
  16. package/dist/Logger.cjs +2 -2
  17. package/dist/Logger.mjs +2 -2
  18. package/dist/Logger.mjs.map +1 -1
  19. package/dist/Middleware.cjs +2 -2
  20. package/dist/Middleware.d.cts +2 -2
  21. package/dist/Middleware.d.mts +2 -2
  22. package/dist/Middleware.mjs +2 -2
  23. package/dist/Middleware.mjs.map +1 -1
  24. package/dist/Profiler.cjs +2 -2
  25. package/dist/Profiler.mjs +2 -2
  26. package/dist/Profiler.mjs.map +1 -1
  27. package/dist/State.cjs +23 -24
  28. package/dist/State.d.cts +22 -23
  29. package/dist/State.d.cts.map +1 -1
  30. package/dist/State.d.mts +22 -23
  31. package/dist/State.d.mts.map +1 -1
  32. package/dist/State.mjs +23 -24
  33. package/dist/State.mjs.map +1 -1
  34. package/dist/index.d.cts +2 -2
  35. package/dist/index.d.mts +2 -2
  36. package/dist/types.d.cts +4 -2
  37. package/dist/types.d.cts.map +1 -1
  38. package/dist/types.d.mts +4 -2
  39. package/dist/types.d.mts.map +1 -1
  40. package/package.json +8 -8
  41. package/src/API.ts +12 -0
  42. package/src/Galena.ts +101 -23
  43. package/src/Logger.ts +2 -2
  44. package/src/Middleware.ts +2 -2
  45. package/src/Profiler.ts +2 -2
  46. package/src/State.ts +23 -24
  47. package/src/types.ts +7 -1
package/dist/State.d.cts CHANGED
@@ -1,19 +1,20 @@
1
1
  import { NonFunction, Setter, Subscriber } from "./types.cjs";
2
2
  import { Middleware } from "./Middleware.cjs";
3
+ import { API } from "./API.cjs";
3
4
 
4
5
  //#region src/State.d.ts
5
6
  /**
6
- * State
7
+ * ### State
7
8
  *
8
9
  * The unit of reactivity for Galena. `State`'s can act
9
10
  * as isolated instances or be part of your global app
10
11
  * state (via `Galena` instances).
11
12
  *
12
- * There are three ways to create state instances
13
+ * There are two ways to create state instances
13
14
  *
14
15
  * ```typescript
15
- * import { State, createState, useState, Profiler } from "@figliolia/galena";
16
- * // for island states that can be shared between react components
16
+ * import { State, createState, Profiler } from "@figliolia/galena";
17
+
17
18
  * const myState = new State("<any value>", ...middleware);
18
19
  * // or
19
20
  * const myState = createState("<any value>", ...middleware);
@@ -22,23 +23,14 @@ import { Middleware } from "./Middleware.cjs";
22
23
  * myState.update(previousValue => "<new-value>");
23
24
  * myState.subscribe(nextValue => {});
24
25
  * myState.registerMiddleware(new Profiler());
25
- *
26
- * // Similarly if you wish to use your state inside a react component
27
- * const MyComponent = () => {
28
- * const [state, setState] = useState(myState);
29
- * // or
30
- * const [state, setState] = useMyState("<any-value>", ...middlware);
31
- *
32
- * return (
33
- * // your jsx
34
- * );
35
- * }
26
+ * myState.reset(); // reset back to it's original value
27
+ * // to get the current value at any point in time
28
+ * const currentValue = myState.getState();
36
29
  * ```
37
30
  */
38
- declare class State<T> {
31
+ declare class State<T> extends API<T, NonFunction<T>> {
39
32
  readonly initialState: NonFunction<T>;
40
33
  private state;
41
- readonly middleware: Middleware<T>[];
42
34
  private readonly Emitter;
43
35
  constructor(initialState: NonFunction<T>, ...middleware: Middleware<T>[]);
44
36
  /**
@@ -69,7 +61,7 @@ declare class State<T> {
69
61
  * Returns the current state. Designed for compatibility with
70
62
  * `useSyncExternalStore`
71
63
  */
72
- readonly getSnapshot: () => NonFunction<T>;
64
+ readonly getState: () => NonFunction<T>;
73
65
  /**
74
66
  * Subscribe
75
67
  *
@@ -91,21 +83,28 @@ declare class State<T> {
91
83
  private invokeMiddleware;
92
84
  }
93
85
  /**
94
- * Create State
86
+ * ### createState
95
87
  *
96
- * Returns the unit of reactivity for Galena. `State`'s can act
88
+ * The unit of reactivity for Galena. `State`'s can act
97
89
  * as isolated instances or be part of your global app
98
- * state (via `Galena` instances);
90
+ * state (via `Galena` instances).
99
91
  *
100
- * ```typescript
101
- * import { createState, Profiler } from "@figliolia/galena";
92
+ * There are two ways to create state instances
102
93
  *
94
+ * ```typescript
95
+ * import { State, createState, Profiler } from "@figliolia/galena";
96
+
97
+ * const myState = new State("<any value>", ...middleware);
98
+ * // or
103
99
  * const myState = createState("<any value>", ...middleware);
104
100
  *
105
101
  * myState.set("<new-value>");
106
102
  * myState.update(previousValue => "<new-value>");
107
103
  * myState.subscribe(nextValue => {});
108
104
  * myState.registerMiddleware(new Profiler());
105
+ * myState.reset(); // reset back to it's original value
106
+ * // to get the current value at any point in time
107
+ * const currentValue = myState.getState();
109
108
  * ```
110
109
  */
111
110
  declare function createState<T>(...args: ConstructorParameters<typeof State<T>>): State<T>;
@@ -1 +1 @@
1
- {"version":3,"file":"State.d.cts","names":[],"sources":["../src/State.ts"],"mappings":";;;;;;AAqCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,KAAA;EAAA,SAKO,YAAA,EAAc,WAAA,CAAY,CAAA;EAAA,QAJpC,KAAA;EAAA,SACQ,UAAA,EAAY,UAAA,CAAW,CAAA;EAAA,iBACtB,OAAA;cAEC,YAAA,EAAc,WAAA,CAAY,CAAA,MACvC,UAAA,EAAY,UAAA,CAAW,CAAA;EADI;;;;;;EAAA,SAahB,GAAA,GAAG,KAAA,EAAA,WAAA,CAAA,CAAA;EAAA;;;;;;;EAAA,SASH,MAAA,GAAM,MAAA,EAAA,MAAA,CAAA,CAAA;EAqBN;;;;;;EAAA,SARA,KAAA;EAgCT;;;;;;EAAA,SAxBS,WAAA,QAAW,WAAA,CAAA,CAAA;EAgDE;;;;;;EAAA,SAtCb,SAAA,GAAa,EAAA,EAAI,UAAA,CAAW,CAAA;EA0CpB;;AAyB1B;;;;;EArDS,kBAAA,CAAA,GAAsB,UAAA,EAAY,UAAA,CAAW,CAAA;EAAA,QAI5C,YAAA;EAAA,QAaA,IAAA;EAAA,UAOE,UAAA,CAAW,MAAA,EAAQ,MAAA,CAAO,CAAA,IAAK,MAAA,IAAU,WAAA,CAAY,CAAA;EAAA,QAIvD,gBAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAyBM,WAAA,GAAA,CAAA,GACX,IAAA,EAAM,qBAAA,QAA6B,KAAA,CAAM,CAAA,KAAG,KAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"State.d.cts","names":[],"sources":["../src/State.ts"],"mappings":";;;;;;;AA8BA;;;;;;;;;;;;;;;;;;;;;;;cAAa,KAAA,YAAiB,GAAA,CAAI,CAAA,EAAG,WAAA,CAAY,CAAA;EAAA,SAI7B,YAAA,EAAc,WAAA,CAAY,CAAA;EAAA,QAHpC,KAAA;EAAA,iBACS,OAAA;cAEC,YAAA,EAAc,WAAA,CAAY,CAAA,MACvC,UAAA,EAAY,UAAA,CAAW,CAAA;EALG;;;;;;EAAA,SAiBf,GAAA,GAAG,KAAA,EAAA,WAAA,CAAA,CAAA;EAba;;;;;;;EAAA,SAsBhB,MAAA,GAAM,MAAA,EAAA,MAAA,CAAA,CAAA;EArBjB;;;;;;EAAA,SAkCW,KAAA;EAbA;;;;;;EAAA,SAqBA,QAAA,QAAQ,WAAA,CAAA,CAAA;EAAA;;;;;;EAAA,SAUR,SAAA,GAAa,EAAA,EAAI,UAAA,CAAW,CAAA;EAcH;;;;;;;EAAlC,kBAAA,CAAA,GAAsB,UAAA,EAAY,UAAA,CAAW,CAAA;EAAA,QAI5C,YAAA;EAAA,QAaA,IAAA;EAAA,UAOE,UAAA,CAAW,MAAA,EAAQ,MAAA,CAAO,CAAA,IAAK,MAAA,IAAU,WAAA,CAAY,CAAA;EAAA,QAIvD,gBAAA;AAAA;;AAgCV;;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,WAAA,GAAA,CAAA,GACX,IAAA,EAAM,qBAAA,QAA6B,KAAA,CAAM,CAAA,KAAG,KAAA,CAAA,CAAA"}
package/dist/State.d.mts CHANGED
@@ -1,19 +1,20 @@
1
1
  import { NonFunction, Setter, Subscriber } from "./types.mjs";
2
2
  import { Middleware } from "./Middleware.mjs";
3
+ import { API } from "./API.mjs";
3
4
 
4
5
  //#region src/State.d.ts
5
6
  /**
6
- * State
7
+ * ### State
7
8
  *
8
9
  * The unit of reactivity for Galena. `State`'s can act
9
10
  * as isolated instances or be part of your global app
10
11
  * state (via `Galena` instances).
11
12
  *
12
- * There are three ways to create state instances
13
+ * There are two ways to create state instances
13
14
  *
14
15
  * ```typescript
15
- * import { State, createState, useState, Profiler } from "@figliolia/galena";
16
- * // for island states that can be shared between react components
16
+ * import { State, createState, Profiler } from "@figliolia/galena";
17
+
17
18
  * const myState = new State("<any value>", ...middleware);
18
19
  * // or
19
20
  * const myState = createState("<any value>", ...middleware);
@@ -22,23 +23,14 @@ import { Middleware } from "./Middleware.mjs";
22
23
  * myState.update(previousValue => "<new-value>");
23
24
  * myState.subscribe(nextValue => {});
24
25
  * myState.registerMiddleware(new Profiler());
25
- *
26
- * // Similarly if you wish to use your state inside a react component
27
- * const MyComponent = () => {
28
- * const [state, setState] = useState(myState);
29
- * // or
30
- * const [state, setState] = useMyState("<any-value>", ...middlware);
31
- *
32
- * return (
33
- * // your jsx
34
- * );
35
- * }
26
+ * myState.reset(); // reset back to it's original value
27
+ * // to get the current value at any point in time
28
+ * const currentValue = myState.getState();
36
29
  * ```
37
30
  */
38
- declare class State<T> {
31
+ declare class State<T> extends API<T, NonFunction<T>> {
39
32
  readonly initialState: NonFunction<T>;
40
33
  private state;
41
- readonly middleware: Middleware<T>[];
42
34
  private readonly Emitter;
43
35
  constructor(initialState: NonFunction<T>, ...middleware: Middleware<T>[]);
44
36
  /**
@@ -69,7 +61,7 @@ declare class State<T> {
69
61
  * Returns the current state. Designed for compatibility with
70
62
  * `useSyncExternalStore`
71
63
  */
72
- readonly getSnapshot: () => NonFunction<T>;
64
+ readonly getState: () => NonFunction<T>;
73
65
  /**
74
66
  * Subscribe
75
67
  *
@@ -91,21 +83,28 @@ declare class State<T> {
91
83
  private invokeMiddleware;
92
84
  }
93
85
  /**
94
- * Create State
86
+ * ### createState
95
87
  *
96
- * Returns the unit of reactivity for Galena. `State`'s can act
88
+ * The unit of reactivity for Galena. `State`'s can act
97
89
  * as isolated instances or be part of your global app
98
- * state (via `Galena` instances);
90
+ * state (via `Galena` instances).
99
91
  *
100
- * ```typescript
101
- * import { createState, Profiler } from "@figliolia/galena";
92
+ * There are two ways to create state instances
102
93
  *
94
+ * ```typescript
95
+ * import { State, createState, Profiler } from "@figliolia/galena";
96
+
97
+ * const myState = new State("<any value>", ...middleware);
98
+ * // or
103
99
  * const myState = createState("<any value>", ...middleware);
104
100
  *
105
101
  * myState.set("<new-value>");
106
102
  * myState.update(previousValue => "<new-value>");
107
103
  * myState.subscribe(nextValue => {});
108
104
  * myState.registerMiddleware(new Profiler());
105
+ * myState.reset(); // reset back to it's original value
106
+ * // to get the current value at any point in time
107
+ * const currentValue = myState.getState();
109
108
  * ```
110
109
  */
111
110
  declare function createState<T>(...args: ConstructorParameters<typeof State<T>>): State<T>;
@@ -1 +1 @@
1
- {"version":3,"file":"State.d.mts","names":[],"sources":["../src/State.ts"],"mappings":";;;;;;AAqCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,KAAA;EAAA,SAKO,YAAA,EAAc,WAAA,CAAY,CAAA;EAAA,QAJpC,KAAA;EAAA,SACQ,UAAA,EAAY,UAAA,CAAW,CAAA;EAAA,iBACtB,OAAA;cAEC,YAAA,EAAc,WAAA,CAAY,CAAA,MACvC,UAAA,EAAY,UAAA,CAAW,CAAA;EADI;;;;;;EAAA,SAahB,GAAA,GAAG,KAAA,EAAA,WAAA,CAAA,CAAA;EAAA;;;;;;;EAAA,SASH,MAAA,GAAM,MAAA,EAAA,MAAA,CAAA,CAAA;EAqBN;;;;;;EAAA,SARA,KAAA;EAgCT;;;;;;EAAA,SAxBS,WAAA,QAAW,WAAA,CAAA,CAAA;EAgDE;;;;;;EAAA,SAtCb,SAAA,GAAa,EAAA,EAAI,UAAA,CAAW,CAAA;EA0CpB;;AAyB1B;;;;;EArDS,kBAAA,CAAA,GAAsB,UAAA,EAAY,UAAA,CAAW,CAAA;EAAA,QAI5C,YAAA;EAAA,QAaA,IAAA;EAAA,UAOE,UAAA,CAAW,MAAA,EAAQ,MAAA,CAAO,CAAA,IAAK,MAAA,IAAU,WAAA,CAAY,CAAA;EAAA,QAIvD,gBAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAyBM,WAAA,GAAA,CAAA,GACX,IAAA,EAAM,qBAAA,QAA6B,KAAA,CAAM,CAAA,KAAG,KAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"State.d.mts","names":[],"sources":["../src/State.ts"],"mappings":";;;;;;;AA8BA;;;;;;;;;;;;;;;;;;;;;;;cAAa,KAAA,YAAiB,GAAA,CAAI,CAAA,EAAG,WAAA,CAAY,CAAA;EAAA,SAI7B,YAAA,EAAc,WAAA,CAAY,CAAA;EAAA,QAHpC,KAAA;EAAA,iBACS,OAAA;cAEC,YAAA,EAAc,WAAA,CAAY,CAAA,MACvC,UAAA,EAAY,UAAA,CAAW,CAAA;EALG;;;;;;EAAA,SAiBf,GAAA,GAAG,KAAA,EAAA,WAAA,CAAA,CAAA;EAba;;;;;;;EAAA,SAsBhB,MAAA,GAAM,MAAA,EAAA,MAAA,CAAA,CAAA;EArBjB;;;;;;EAAA,SAkCW,KAAA;EAbA;;;;;;EAAA,SAqBA,QAAA,QAAQ,WAAA,CAAA,CAAA;EAAA;;;;;;EAAA,SAUR,SAAA,GAAa,EAAA,EAAI,UAAA,CAAW,CAAA;EAcH;;;;;;;EAAlC,kBAAA,CAAA,GAAsB,UAAA,EAAY,UAAA,CAAW,CAAA;EAAA,QAI5C,YAAA;EAAA,QAaA,IAAA;EAAA,UAOE,UAAA,CAAW,MAAA,EAAQ,MAAA,CAAO,CAAA,IAAK,MAAA,IAAU,WAAA,CAAY,CAAA;EAAA,QAIvD,gBAAA;AAAA;;AAgCV;;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,WAAA,GAAA,CAAA,GACX,IAAA,EAAM,qBAAA,QAA6B,KAAA,CAAM,CAAA,KAAG,KAAA,CAAA,CAAA"}
package/dist/State.mjs CHANGED
@@ -1,17 +1,18 @@
1
+ import { API } from "./API.mjs";
1
2
  import { EventEmitter } from "@figliolia/event-emitter";
2
3
  //#region src/State.ts
3
4
  /**
4
- * State
5
+ * ### State
5
6
  *
6
7
  * The unit of reactivity for Galena. `State`'s can act
7
8
  * as isolated instances or be part of your global app
8
9
  * state (via `Galena` instances).
9
10
  *
10
- * There are three ways to create state instances
11
+ * There are two ways to create state instances
11
12
  *
12
13
  * ```typescript
13
- * import { State, createState, useState, Profiler } from "@figliolia/galena";
14
- * // for island states that can be shared between react components
14
+ * import { State, createState, Profiler } from "@figliolia/galena";
15
+
15
16
  * const myState = new State("<any value>", ...middleware);
16
17
  * // or
17
18
  * const myState = createState("<any value>", ...middleware);
@@ -20,27 +21,18 @@ import { EventEmitter } from "@figliolia/event-emitter";
20
21
  * myState.update(previousValue => "<new-value>");
21
22
  * myState.subscribe(nextValue => {});
22
23
  * myState.registerMiddleware(new Profiler());
23
- *
24
- * // Similarly if you wish to use your state inside a react component
25
- * const MyComponent = () => {
26
- * const [state, setState] = useState(myState);
27
- * // or
28
- * const [state, setState] = useMyState("<any-value>", ...middlware);
29
- *
30
- * return (
31
- * // your jsx
32
- * );
33
- * }
24
+ * myState.reset(); // reset back to it's original value
25
+ * // to get the current value at any point in time
26
+ * const currentValue = myState.getState();
34
27
  * ```
35
28
  */
36
- var State = class {
29
+ var State = class extends API {
37
30
  state;
38
- middleware = [];
39
31
  Emitter = new EventEmitter();
40
32
  constructor(initialState, ...middleware) {
33
+ super(...middleware);
41
34
  this.initialState = initialState;
42
35
  this.state = initialState;
43
- this.registerMiddleware(...middleware);
44
36
  }
45
37
  /**
46
38
  * Set
@@ -73,7 +65,7 @@ var State = class {
73
65
  * Returns the current state. Designed for compatibility with
74
66
  * `useSyncExternalStore`
75
67
  */
76
- getSnapshot = () => {
68
+ getState = () => {
77
69
  return this.state;
78
70
  };
79
71
  /**
@@ -122,21 +114,28 @@ var State = class {
122
114
  }
123
115
  };
124
116
  /**
125
- * Create State
117
+ * ### createState
126
118
  *
127
- * Returns the unit of reactivity for Galena. `State`'s can act
119
+ * The unit of reactivity for Galena. `State`'s can act
128
120
  * as isolated instances or be part of your global app
129
- * state (via `Galena` instances);
121
+ * state (via `Galena` instances).
130
122
  *
131
- * ```typescript
132
- * import { createState, Profiler } from "@figliolia/galena";
123
+ * There are two ways to create state instances
133
124
  *
125
+ * ```typescript
126
+ * import { State, createState, Profiler } from "@figliolia/galena";
127
+
128
+ * const myState = new State("<any value>", ...middleware);
129
+ * // or
134
130
  * const myState = createState("<any value>", ...middleware);
135
131
  *
136
132
  * myState.set("<new-value>");
137
133
  * myState.update(previousValue => "<new-value>");
138
134
  * myState.subscribe(nextValue => {});
139
135
  * myState.registerMiddleware(new Profiler());
136
+ * myState.reset(); // reset back to it's original value
137
+ * // to get the current value at any point in time
138
+ * const currentValue = myState.getState();
140
139
  * ```
141
140
  */
142
141
  function createState(...args) {
@@ -1 +1 @@
1
- {"version":3,"file":"State.mjs","names":[],"sources":["../src/State.ts"],"sourcesContent":["import { EventEmitter } from \"@figliolia/event-emitter\";\nimport type { Middleware } from \"./Middleware\";\nimport type { NonFunction, Setter, Subscriber } from \"./types\";\n\n/**\n * State\n *\n * The unit of reactivity for Galena. `State`'s can act\n * as isolated instances or be part of your global app\n * state (via `Galena` instances).\n *\n * There are three ways to create state instances\n *\n * ```typescript\n * import { State, createState, useState, Profiler } from \"@figliolia/galena\";\n * // for island states that can be shared between react components\n * const myState = new State(\"<any value>\", ...middleware);\n * // or\n * const myState = createState(\"<any value>\", ...middleware);\n *\n * myState.set(\"<new-value>\");\n * myState.update(previousValue => \"<new-value>\");\n * myState.subscribe(nextValue => {});\n * myState.registerMiddleware(new Profiler());\n *\n * // Similarly if you wish to use your state inside a react component\n * const MyComponent = () => {\n * const [state, setState] = useState(myState);\n * // or\n * const [state, setState] = useMyState(\"<any-value>\", ...middlware);\n *\n * return (\n * // your jsx\n * );\n * }\n * ```\n */\nexport class State<T> {\n private state: NonFunction<T>;\n public readonly middleware: Middleware<T>[] = [];\n private readonly Emitter = new EventEmitter<{ change: NonFunction<T> }>();\n constructor(\n public readonly initialState: NonFunction<T>,\n ...middleware: Middleware<T>[]\n ) {\n this.state = initialState;\n this.registerMiddleware(...middleware);\n }\n\n /**\n * Set\n *\n * Updates the current value of state notifying\n * all interested parties\n */\n public readonly set = this.withEmission((state: NonFunction<T>) => state);\n\n /**\n * Update\n *\n * Updates the current value of state using a setter function\n * receiving the previous state as a parameter. Notifies all\n * interested parties\n */\n public readonly update = this.withEmission((setter: Setter<T>) => {\n if (this.diffSetter(setter)) {\n return setter;\n }\n return setter(this.state);\n });\n\n /**\n * Reset\n *\n * Resets the current state back to the state which the instance\n * was initialized with. Notifies all interested parties\n */\n public readonly reset = this.withEmission(() => this.initialState);\n\n /**\n * Get Snapshot\n *\n * Returns the current state. Designed for compatibility with\n * `useSyncExternalStore`\n */\n public readonly getSnapshot = () => {\n return this.state;\n };\n\n /**\n * Subscribe\n *\n * Registers a callback to be executed each time state\n * changes. Returns an `unsubscribe` function\n */\n public readonly subscribe = (fn: Subscriber<T>) => {\n const ID = this.Emitter.on(\"change\", fn);\n return () => {\n this.Emitter.off(\"change\", ID);\n };\n };\n\n /**\n * Register Middleware\n *\n * Registers any number of `Middleware` instances on the\n * current instance of `State`. Your middleware will begin\n * executing at the next state transition\n */\n public registerMiddleware(...middleware: Middleware<T>[]) {\n this.middleware.push(...middleware);\n }\n\n private withEmission<\n F extends (...args: any[]) => NonFunction<T> | Promise<NonFunction<T>>,\n >(fn: F) {\n return (...args: Parameters<F>) => {\n const result = fn(...args);\n if (result instanceof Promise) {\n void result.then(resolved => this.emit(resolved));\n return;\n }\n return this.emit(result);\n };\n }\n\n private emit(nextState: NonFunction<T>) {\n this.invokeMiddleware(\"onBeforeUpdate\");\n this.state = nextState;\n this.Emitter.emit(\"change\", this.state);\n this.invokeMiddleware(\"onUpdate\");\n }\n\n protected diffSetter(setter: Setter<T>): setter is NonFunction<T> {\n return typeof setter !== \"function\";\n }\n\n private invokeMiddleware<K extends keyof Middleware<T>>(fn: K) {\n for (const middleware of this.middleware) {\n middleware[fn](this);\n }\n }\n}\n\n/**\n * Create State\n *\n * Returns the unit of reactivity for Galena. `State`'s can act\n * as isolated instances or be part of your global app\n * state (via `Galena` instances);\n *\n * ```typescript\n * import { createState, Profiler } from \"@figliolia/galena\";\n *\n * const myState = createState(\"<any value>\", ...middleware);\n *\n * myState.set(\"<new-value>\");\n * myState.update(previousValue => \"<new-value>\");\n * myState.subscribe(nextValue => {});\n * myState.registerMiddleware(new Profiler());\n * ```\n */\nexport function createState<T>(\n ...args: ConstructorParameters<typeof State<T>>\n) {\n return new State<T>(...args);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,IAAa,QAAb,MAAsB;CACpB;CACA,aAA8C,EAAE;CAChD,UAA2B,IAAI,cAA0C;CACzE,YACE,cACA,GAAG,YACH;AAFgB,OAAA,eAAA;AAGhB,OAAK,QAAQ;AACb,OAAK,mBAAmB,GAAG,WAAW;;;;;;;;CASxC,MAAsB,KAAK,cAAc,UAA0B,MAAM;;;;;;;;CASzE,SAAyB,KAAK,cAAc,WAAsB;AAChE,MAAI,KAAK,WAAW,OAAO,CACzB,QAAO;AAET,SAAO,OAAO,KAAK,MAAM;GACzB;;;;;;;CAQF,QAAwB,KAAK,mBAAmB,KAAK,aAAa;;;;;;;CAQlE,oBAAoC;AAClC,SAAO,KAAK;;;;;;;;CASd,aAA6B,OAAsB;EACjD,MAAM,KAAK,KAAK,QAAQ,GAAG,UAAU,GAAG;AACxC,eAAa;AACX,QAAK,QAAQ,IAAI,UAAU,GAAG;;;;;;;;;;CAWlC,mBAA0B,GAAG,YAA6B;AACxD,OAAK,WAAW,KAAK,GAAG,WAAW;;CAGrC,aAEE,IAAO;AACP,UAAQ,GAAG,SAAwB;GACjC,MAAM,SAAS,GAAG,GAAG,KAAK;AAC1B,OAAI,kBAAkB,SAAS;AACxB,WAAO,MAAK,aAAY,KAAK,KAAK,SAAS,CAAC;AACjD;;AAEF,UAAO,KAAK,KAAK,OAAO;;;CAI5B,KAAa,WAA2B;AACtC,OAAK,iBAAiB,iBAAiB;AACvC,OAAK,QAAQ;AACb,OAAK,QAAQ,KAAK,UAAU,KAAK,MAAM;AACvC,OAAK,iBAAiB,WAAW;;CAGnC,WAAqB,QAA6C;AAChE,SAAO,OAAO,WAAW;;CAG3B,iBAAwD,IAAO;AAC7D,OAAK,MAAM,cAAc,KAAK,WAC5B,YAAW,IAAI,KAAK;;;;;;;;;;;;;;;;;;;;;AAuB1B,SAAgB,YACd,GAAG,MACH;AACA,QAAO,IAAI,MAAS,GAAG,KAAK"}
1
+ {"version":3,"file":"State.mjs","names":[],"sources":["../src/State.ts"],"sourcesContent":["import { EventEmitter } from \"@figliolia/event-emitter\";\nimport { API } from \"./API\";\nimport type { Middleware } from \"./Middleware\";\nimport type { NonFunction, Setter, Subscriber } from \"./types\";\n\n/**\n * ### State\n *\n * The unit of reactivity for Galena. `State`'s can act\n * as isolated instances or be part of your global app\n * state (via `Galena` instances).\n *\n * There are two ways to create state instances\n *\n * ```typescript\n * import { State, createState, Profiler } from \"@figliolia/galena\";\n \n * const myState = new State(\"<any value>\", ...middleware);\n * // or\n * const myState = createState(\"<any value>\", ...middleware);\n *\n * myState.set(\"<new-value>\");\n * myState.update(previousValue => \"<new-value>\");\n * myState.subscribe(nextValue => {});\n * myState.registerMiddleware(new Profiler());\n * myState.reset(); // reset back to it's original value\n * // to get the current value at any point in time\n * const currentValue = myState.getState();\n * ```\n */\nexport class State<T> extends API<T, NonFunction<T>> {\n private state: NonFunction<T>;\n private readonly Emitter = new EventEmitter<{ change: NonFunction<T> }>();\n constructor(\n public readonly initialState: NonFunction<T>,\n ...middleware: Middleware<T>[]\n ) {\n super(...middleware);\n this.state = initialState;\n }\n\n /**\n * Set\n *\n * Updates the current value of state notifying\n * all interested parties\n */\n public readonly set = this.withEmission((state: NonFunction<T>) => state);\n\n /**\n * Update\n *\n * Updates the current value of state using a setter function\n * receiving the previous state as a parameter. Notifies all\n * interested parties\n */\n public readonly update = this.withEmission((setter: Setter<T>) => {\n if (this.diffSetter(setter)) {\n return setter;\n }\n return setter(this.state);\n });\n\n /**\n * Reset\n *\n * Resets the current state back to the state which the instance\n * was initialized with. Notifies all interested parties\n */\n public readonly reset = this.withEmission(() => this.initialState);\n\n /**\n * Get Snapshot\n *\n * Returns the current state. Designed for compatibility with\n * `useSyncExternalStore`\n */\n public readonly getState = () => {\n return this.state;\n };\n\n /**\n * Subscribe\n *\n * Registers a callback to be executed each time state\n * changes. Returns an `unsubscribe` function\n */\n public readonly subscribe = (fn: Subscriber<T>) => {\n const ID = this.Emitter.on(\"change\", fn);\n return () => {\n this.Emitter.off(\"change\", ID);\n };\n };\n\n /**\n * Register Middleware\n *\n * Registers any number of `Middleware` instances on the\n * current instance of `State`. Your middleware will begin\n * executing at the next state transition\n */\n public registerMiddleware(...middleware: Middleware<T>[]) {\n this.middleware.push(...middleware);\n }\n\n private withEmission<\n F extends (...args: any[]) => NonFunction<T> | Promise<NonFunction<T>>,\n >(fn: F) {\n return (...args: Parameters<F>) => {\n const result = fn(...args);\n if (result instanceof Promise) {\n void result.then(resolved => this.emit(resolved));\n return;\n }\n return this.emit(result);\n };\n }\n\n private emit(nextState: NonFunction<T>) {\n this.invokeMiddleware(\"onBeforeUpdate\");\n this.state = nextState;\n this.Emitter.emit(\"change\", this.state);\n this.invokeMiddleware(\"onUpdate\");\n }\n\n protected diffSetter(setter: Setter<T>): setter is NonFunction<T> {\n return typeof setter !== \"function\";\n }\n\n private invokeMiddleware<K extends keyof Middleware<T>>(fn: K) {\n for (const middleware of this.middleware) {\n middleware[fn](this);\n }\n }\n}\n\n/**\n * ### createState\n *\n * The unit of reactivity for Galena. `State`'s can act\n * as isolated instances or be part of your global app\n * state (via `Galena` instances).\n *\n * There are two ways to create state instances\n *\n * ```typescript\n * import { State, createState, Profiler } from \"@figliolia/galena\";\n \n * const myState = new State(\"<any value>\", ...middleware);\n * // or\n * const myState = createState(\"<any value>\", ...middleware);\n *\n * myState.set(\"<new-value>\");\n * myState.update(previousValue => \"<new-value>\");\n * myState.subscribe(nextValue => {});\n * myState.registerMiddleware(new Profiler());\n * myState.reset(); // reset back to it's original value\n * // to get the current value at any point in time\n * const currentValue = myState.getState();\n * ```\n */\nexport function createState<T>(\n ...args: ConstructorParameters<typeof State<T>>\n) {\n return new State<T>(...args);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,IAAa,QAAb,cAA8B,IAAuB;CACnD;CACA,UAA2B,IAAI,cAA0C;CACzE,YACE,cACA,GAAG,YACH;AACA,QAAM,GAAG,WAAW;AAHJ,OAAA,eAAA;AAIhB,OAAK,QAAQ;;;;;;;;CASf,MAAsB,KAAK,cAAc,UAA0B,MAAM;;;;;;;;CASzE,SAAyB,KAAK,cAAc,WAAsB;AAChE,MAAI,KAAK,WAAW,OAAO,CACzB,QAAO;AAET,SAAO,OAAO,KAAK,MAAM;GACzB;;;;;;;CAQF,QAAwB,KAAK,mBAAmB,KAAK,aAAa;;;;;;;CAQlE,iBAAiC;AAC/B,SAAO,KAAK;;;;;;;;CASd,aAA6B,OAAsB;EACjD,MAAM,KAAK,KAAK,QAAQ,GAAG,UAAU,GAAG;AACxC,eAAa;AACX,QAAK,QAAQ,IAAI,UAAU,GAAG;;;;;;;;;;CAWlC,mBAA0B,GAAG,YAA6B;AACxD,OAAK,WAAW,KAAK,GAAG,WAAW;;CAGrC,aAEE,IAAO;AACP,UAAQ,GAAG,SAAwB;GACjC,MAAM,SAAS,GAAG,GAAG,KAAK;AAC1B,OAAI,kBAAkB,SAAS;AACxB,WAAO,MAAK,aAAY,KAAK,KAAK,SAAS,CAAC;AACjD;;AAEF,UAAO,KAAK,KAAK,OAAO;;;CAI5B,KAAa,WAA2B;AACtC,OAAK,iBAAiB,iBAAiB;AACvC,OAAK,QAAQ;AACb,OAAK,QAAQ,KAAK,UAAU,KAAK,MAAM;AACvC,OAAK,iBAAiB,WAAW;;CAGnC,WAAqB,QAA6C;AAChE,SAAO,OAAO,WAAW;;CAG3B,iBAAwD,IAAO;AAC7D,OAAK,MAAM,cAAc,KAAK,WAC5B,YAAW,IAAI,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8B1B,SAAgB,YACd,GAAG,MACH;AACA,QAAO,IAAI,MAAS,GAAG,KAAK"}
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- import { AppSubscriber, GalenaSnapshot, NonFunction, PartialSupport, Setter, StateTypes, Subscriber } from "./types.cjs";
1
+ import { AppSubscriber, GalenaSnapshot, GalenaState, NonFunction, PartialSupport, Setter, StateType, StateTypes, Subscriber } from "./types.cjs";
2
2
  import { State, createState } from "./State.cjs";
3
3
  import { Middleware } from "./Middleware.cjs";
4
4
  import { Galena, createGalena } from "./Galena.cjs";
5
5
  import { Logger } from "./Logger.cjs";
6
6
  import { Profiler } from "./Profiler.cjs";
7
- export { AppSubscriber, Galena, GalenaSnapshot, Logger, Middleware, NonFunction, PartialSupport, Profiler, Setter, State, StateTypes, Subscriber, createGalena, createState };
7
+ export { AppSubscriber, Galena, GalenaSnapshot, GalenaState, Logger, Middleware, NonFunction, PartialSupport, Profiler, Setter, State, StateType, StateTypes, Subscriber, createGalena, createState };
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { AppSubscriber, GalenaSnapshot, NonFunction, PartialSupport, Setter, StateTypes, Subscriber } from "./types.mjs";
1
+ import { AppSubscriber, GalenaSnapshot, GalenaState, NonFunction, PartialSupport, Setter, StateType, StateTypes, Subscriber } from "./types.mjs";
2
2
  import { State, createState } from "./State.mjs";
3
3
  import { Middleware } from "./Middleware.mjs";
4
4
  import { Galena, createGalena } from "./Galena.mjs";
5
5
  import { Logger } from "./Logger.mjs";
6
6
  import { Profiler } from "./Profiler.mjs";
7
- export { AppSubscriber, Galena, GalenaSnapshot, Logger, Middleware, NonFunction, PartialSupport, Profiler, Setter, State, StateTypes, Subscriber, createGalena, createState };
7
+ export { AppSubscriber, Galena, GalenaSnapshot, GalenaState, Logger, Middleware, NonFunction, PartialSupport, Profiler, Setter, State, StateType, StateTypes, Subscriber, createGalena, createState };
package/dist/types.d.cts CHANGED
@@ -10,7 +10,9 @@ interface GalenaSnapshot<T extends Record<string, State<any>>, K extends Extract
10
10
  state: T;
11
11
  }
12
12
  type AppSubscriber<T extends Record<string, State<any>>, K extends Extract<keyof T, string> = Extract<keyof T, string>> = ((payload: GalenaSnapshot<T, K>) => void) | (() => void);
13
- type StateTypes<T extends Record<string, State<any>>> = ReturnType<T[keyof T]["getSnapshot"]>;
13
+ type StateTypes<T extends Record<string, State<any>>> = ReturnType<StateType<T[keyof T]>>;
14
+ type StateType<T extends State<any>> = ReturnType<T["getState"]>;
15
+ type GalenaState<T extends Record<string, State<any>>> = { [K in keyof T]: StateType<T[K]> };
14
16
  //#endregion
15
- export { AppSubscriber, GalenaSnapshot, NonFunction, PartialSupport, Setter, StateTypes, Subscriber };
17
+ export { AppSubscriber, GalenaSnapshot, GalenaState, NonFunction, PartialSupport, Setter, StateType, StateTypes, Subscriber };
16
18
  //# sourceMappingURL=types.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"mappings":";;;KAEY,WAAA,MAAiB,CAAA,cAAc,IAAA,2BAA8B,CAAA;AAAA,KAE7D,cAAA,MAAoB,CAAA,SAAU,MAAA,gBAAsB,OAAA,CAAQ,CAAA,IAAK,CAAA;AAAA,KAEjE,MAAA,MACR,WAAA,CAAY,CAAA,MACV,SAAA,EAAW,WAAA,CAAY,CAAA,MAAO,WAAA,CAAY,CAAA,IAAK,OAAA,CAAQ,WAAA,CAAY,CAAA;AAAA,KAE7D,UAAA,QAAkB,KAAA,EAAO,WAAA,CAAY,CAAA;AAAA,UAEhC,cAAA,WACL,MAAA,SAAe,KAAA,kBACf,OAAA,OAAc,CAAA,YAAa,OAAA,OAAc,CAAA;EAEnD,OAAA,EAAS,CAAA,CAAE,CAAA;EACX,KAAA,EAAO,CAAA;AAAA;AAAA,KAGG,aAAA,WACA,MAAA,SAAe,KAAA,kBACf,OAAA,OAAc,CAAA,YAAa,OAAA,OAAc,CAAA,eAC/C,OAAA,EAAS,cAAA,CAAe,CAAA,EAAG,CAAA;AAAA,KAErB,UAAA,WAAqB,MAAA,SAAe,KAAA,UAAe,UAAA,CAC7D,CAAA,OAAQ,CAAA"}
1
+ {"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"mappings":";;;KAEY,WAAA,MAAiB,CAAA,cAAc,IAAA,2BAA8B,CAAA;AAAA,KAE7D,cAAA,MAAoB,CAAA,SAAU,MAAA,gBAAsB,OAAA,CAAQ,CAAA,IAAK,CAAA;AAAA,KAEjE,MAAA,MACR,WAAA,CAAY,CAAA,MACV,SAAA,EAAW,WAAA,CAAY,CAAA,MAAO,WAAA,CAAY,CAAA,IAAK,OAAA,CAAQ,WAAA,CAAY,CAAA;AAAA,KAE7D,UAAA,QAAkB,KAAA,EAAO,WAAA,CAAY,CAAA;AAAA,UAEhC,cAAA,WACL,MAAA,SAAe,KAAA,kBACf,OAAA,OAAc,CAAA,YAAa,OAAA,OAAc,CAAA;EAEnD,OAAA,EAAS,CAAA,CAAE,CAAA;EACX,KAAA,EAAO,CAAA;AAAA;AAAA,KAGG,aAAA,WACA,MAAA,SAAe,KAAA,kBACf,OAAA,OAAc,CAAA,YAAa,OAAA,OAAc,CAAA,eAC/C,OAAA,EAAS,cAAA,CAAe,CAAA,EAAG,CAAA;AAAA,KAErB,UAAA,WAAqB,MAAA,SAAe,KAAA,UAAe,UAAA,CAC7D,SAAA,CAAU,CAAA,OAAQ,CAAA;AAAA,KAGR,SAAA,WAAoB,KAAA,SAAc,UAAA,CAAW,CAAA;AAAA,KAE7C,WAAA,WAAsB,MAAA,SAAe,KAAA,wBACnC,CAAA,GAAI,SAAA,CAAU,CAAA,CAAE,CAAA"}
package/dist/types.d.mts CHANGED
@@ -10,7 +10,9 @@ interface GalenaSnapshot<T extends Record<string, State<any>>, K extends Extract
10
10
  state: T;
11
11
  }
12
12
  type AppSubscriber<T extends Record<string, State<any>>, K extends Extract<keyof T, string> = Extract<keyof T, string>> = ((payload: GalenaSnapshot<T, K>) => void) | (() => void);
13
- type StateTypes<T extends Record<string, State<any>>> = ReturnType<T[keyof T]["getSnapshot"]>;
13
+ type StateTypes<T extends Record<string, State<any>>> = ReturnType<StateType<T[keyof T]>>;
14
+ type StateType<T extends State<any>> = ReturnType<T["getState"]>;
15
+ type GalenaState<T extends Record<string, State<any>>> = { [K in keyof T]: StateType<T[K]> };
14
16
  //#endregion
15
- export { AppSubscriber, GalenaSnapshot, NonFunction, PartialSupport, Setter, StateTypes, Subscriber };
17
+ export { AppSubscriber, GalenaSnapshot, GalenaState, NonFunction, PartialSupport, Setter, StateType, StateTypes, Subscriber };
16
18
  //# sourceMappingURL=types.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;KAEY,WAAA,MAAiB,CAAA,cAAc,IAAA,2BAA8B,CAAA;AAAA,KAE7D,cAAA,MAAoB,CAAA,SAAU,MAAA,gBAAsB,OAAA,CAAQ,CAAA,IAAK,CAAA;AAAA,KAEjE,MAAA,MACR,WAAA,CAAY,CAAA,MACV,SAAA,EAAW,WAAA,CAAY,CAAA,MAAO,WAAA,CAAY,CAAA,IAAK,OAAA,CAAQ,WAAA,CAAY,CAAA;AAAA,KAE7D,UAAA,QAAkB,KAAA,EAAO,WAAA,CAAY,CAAA;AAAA,UAEhC,cAAA,WACL,MAAA,SAAe,KAAA,kBACf,OAAA,OAAc,CAAA,YAAa,OAAA,OAAc,CAAA;EAEnD,OAAA,EAAS,CAAA,CAAE,CAAA;EACX,KAAA,EAAO,CAAA;AAAA;AAAA,KAGG,aAAA,WACA,MAAA,SAAe,KAAA,kBACf,OAAA,OAAc,CAAA,YAAa,OAAA,OAAc,CAAA,eAC/C,OAAA,EAAS,cAAA,CAAe,CAAA,EAAG,CAAA;AAAA,KAErB,UAAA,WAAqB,MAAA,SAAe,KAAA,UAAe,UAAA,CAC7D,CAAA,OAAQ,CAAA"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;KAEY,WAAA,MAAiB,CAAA,cAAc,IAAA,2BAA8B,CAAA;AAAA,KAE7D,cAAA,MAAoB,CAAA,SAAU,MAAA,gBAAsB,OAAA,CAAQ,CAAA,IAAK,CAAA;AAAA,KAEjE,MAAA,MACR,WAAA,CAAY,CAAA,MACV,SAAA,EAAW,WAAA,CAAY,CAAA,MAAO,WAAA,CAAY,CAAA,IAAK,OAAA,CAAQ,WAAA,CAAY,CAAA;AAAA,KAE7D,UAAA,QAAkB,KAAA,EAAO,WAAA,CAAY,CAAA;AAAA,UAEhC,cAAA,WACL,MAAA,SAAe,KAAA,kBACf,OAAA,OAAc,CAAA,YAAa,OAAA,OAAc,CAAA;EAEnD,OAAA,EAAS,CAAA,CAAE,CAAA;EACX,KAAA,EAAO,CAAA;AAAA;AAAA,KAGG,aAAA,WACA,MAAA,SAAe,KAAA,kBACf,OAAA,OAAc,CAAA,YAAa,OAAA,OAAc,CAAA,eAC/C,OAAA,EAAS,cAAA,CAAe,CAAA,EAAG,CAAA;AAAA,KAErB,UAAA,WAAqB,MAAA,SAAe,KAAA,UAAe,UAAA,CAC7D,SAAA,CAAU,CAAA,OAAQ,CAAA;AAAA,KAGR,SAAA,WAAoB,KAAA,SAAc,UAAA,CAAW,CAAA;AAAA,KAE7C,WAAA,WAAsB,MAAA,SAAe,KAAA,wBACnC,CAAA,GAAI,SAAA,CAAU,CAAA,CAAE,CAAA"}
package/package.json CHANGED
@@ -1,7 +1,13 @@
1
1
  {
2
2
  "name": "@figliolia/galena",
3
- "version": "3.0.2",
3
+ "version": "4.0.0",
4
4
  "description": "A performant state management library supporting middleware and a rich developer API",
5
+ "keywords": [
6
+ "flux",
7
+ "react",
8
+ "state",
9
+ "state management"
10
+ ],
5
11
  "homepage": "https://github.com/alexfigliolia/galena#readme",
6
12
  "license": "MIT",
7
13
  "author": "Alex Figliolia",
@@ -48,11 +54,5 @@
48
54
  },
49
55
  "peerDependencies": {
50
56
  "@figliolia/event-emitter": ">=1.2.0"
51
- },
52
- "keywords": [
53
- "state",
54
- "state management",
55
- "flux",
56
- "react"
57
- ]
57
+ }
58
58
  }
package/src/API.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { Middleware } from "./Middleware";
2
+
3
+ export abstract class API<T, E, M = T> {
4
+ public readonly middleware: Middleware<M>[] = [];
5
+ constructor(...middleware: Middleware<M>[]) {
6
+ this.registerMiddleware(...middleware);
7
+ }
8
+
9
+ public abstract getState(): T;
10
+ public abstract subscribe(subscriber: (payload: E) => void): () => void;
11
+ public abstract registerMiddleware(...middlewares: Middleware<M>[]): void;
12
+ }
package/src/Galena.ts CHANGED
@@ -1,52 +1,117 @@
1
1
  import { EventEmitter } from "@figliolia/event-emitter";
2
+ import { API } from "./API";
2
3
  import type { Middleware } from "./Middleware";
3
4
  import type { State } from "./State";
4
- import type { AppSubscriber, GalenaSnapshot, StateTypes } from "./types";
5
+ import type {
6
+ AppSubscriber,
7
+ GalenaSnapshot,
8
+ GalenaState,
9
+ Setter,
10
+ StateType,
11
+ StateTypes,
12
+ } from "./types";
5
13
 
6
14
  /**
7
- * Galena
15
+ * ### Galena
8
16
  *
9
- * Galena is designed to house one or more units of `State`
17
+ * Galena instances are designed to house one or more units of `State`
10
18
  * and exist as a pseudo global application state.
11
19
  *
12
20
  * By design, each of its `State` units have isolated reactivity
13
21
  * that prevents entire state trees from updating when a single
14
22
  * unit changes.
15
23
  *
16
- * This is dissimilar to redux-like models where downstream reconciliations
17
- * will propagate everwhere a given store is read from. In galena, downstream
18
- * reconciliations occur only for consumers of the slice of state that
19
- * changed - making it safer to use with more frequent state changes.
20
- *
21
24
  * ```typescript
22
25
  * import { Galena } from "@figliolia/galena";
23
26
  *
24
27
  * const AppState = new Galena({
28
+ * user: new State("<user-stuff>"),
29
+ * business: new State("<business-logic-stuff>")
25
30
  * // your reactive instances
26
31
  * }, ...middleware);
27
32
  *
28
33
  * // to retreive and work with an individual unit
29
- * const myUnit = AppState.get("<key>"); // Returns State<T>
34
+ * const userState = AppState.get("user"); // Returns State<T>
30
35
  *
31
36
  * // to run a callback anytime a unit of state changes
32
- * const unsubscribe = AppState.subscribe(({ updated }) => {
37
+ * const listener = AppState.subscribe(({ state, updated }) => {
33
38
  * // do something with the `State` instance that updated
39
+ * // the entirety of your state
34
40
  * });
41
+ *
42
+ * // get the current application state
43
+ * const currentState = AppState.getState();
44
+ *
45
+ * // operate on an instance of state
46
+ * AppState.update("user", userState => ({
47
+ * ...userState,
48
+ * // your updates
49
+ * }));
35
50
  * ```
36
51
  */
37
- export class Galena<T extends Record<string, State<any>>> {
52
+ export class Galena<T extends Record<string, State<any>>> extends API<
53
+ GalenaState<T>,
54
+ GalenaSnapshot<T>,
55
+ StateTypes<T>
56
+ > {
38
57
  private Emitter = new EventEmitter<{ change: GalenaSnapshot<T> }>();
39
58
  constructor(
40
59
  public readonly state: T,
41
60
  ...middleware: Middleware<StateTypes<T>>[]
42
61
  ) {
43
- this.registerMiddleware(...middleware);
62
+ super(...middleware);
44
63
  }
45
64
 
65
+ public getState() {
66
+ const result = {} as GalenaState<T>;
67
+ for (const key in this.state) {
68
+ const state = key as keyof T;
69
+ result[state] = this.state[key].getState();
70
+ }
71
+ return result;
72
+ }
73
+
74
+ /**
75
+ * Get
76
+ *
77
+ * Returns a connected State instance by key
78
+ */
46
79
  public get<K extends Extract<keyof T, string>>(key: K) {
47
80
  return this.state[key];
48
81
  }
49
82
 
83
+ /**
84
+ * Set
85
+ *
86
+ * Sets a connected State instance's state by key
87
+ */
88
+ public set<K extends Extract<keyof T, string>>(
89
+ key: K,
90
+ value: StateType<T[K]>,
91
+ ) {
92
+ return this.get(key).set(value);
93
+ }
94
+
95
+ /**
96
+ * Update
97
+ *
98
+ * Invokes a connected State instance's update method key
99
+ */
100
+ public update<K extends Extract<keyof T, string>>(
101
+ key: K,
102
+ updater: Setter<StateType<T[K]>>,
103
+ ) {
104
+ return this.get(key).update(updater);
105
+ }
106
+
107
+ /**
108
+ * Subscribe
109
+ *
110
+ * Listen for changes on your Galena instnace. Your provided
111
+ * callback will be invoked each time an attached state instance
112
+ * changes. To your callback will be provided the `updated` state
113
+ * instance, along with the entire `state` tree
114
+ */
50
115
  public subscribe = (subscriber: AppSubscriber<T>) => {
51
116
  const ID = this.Emitter.on("change", subscriber);
52
117
  const unsubscribers: (() => void)[] = [];
@@ -69,6 +134,12 @@ export class Galena<T extends Record<string, State<any>>> {
69
134
  };
70
135
  };
71
136
 
137
+ /**
138
+ * Register Middleware
139
+ *
140
+ * Adds middleware instances to each of the connected
141
+ * `State` instances
142
+ */
72
143
  public registerMiddleware(...middlewares: Middleware<StateTypes<T>>[]) {
73
144
  for (const key in this.state) {
74
145
  this.state[key]?.registerMiddleware?.(...middlewares);
@@ -83,34 +154,41 @@ export class Galena<T extends Record<string, State<any>>> {
83
154
  }
84
155
 
85
156
  /**
86
- * Create Galena
157
+ * ### createGalena
87
158
  *
88
- * Galena is designed to house one or more units of `State`
159
+ * Galena instances are designed to house one or more units of `State`
89
160
  * and exist as a pseudo global application state.
90
161
  *
91
162
  * By design, each of its `State` units have isolated reactivity
92
163
  * that prevents entire state trees from updating when a single
93
164
  * unit changes.
94
165
  *
95
- * This is dissimilar to redux-like models where downstream reconciliations
96
- * will propagate everwhere a given store is read from. In galena, downstream
97
- * reconciliations occur only for consumers of the slice of state that
98
- * changed - making it safer to use with more frequent state changes.
99
- *
100
166
  * ```typescript
101
- * import { createGalena } from "@figliolia/galena";
167
+ * import { Galena } from "@figliolia/galena";
102
168
  *
103
- * const AppState = createGalena({
169
+ * const AppState = new Galena({
170
+ * user: new State("<user-stuff>"),
171
+ * business: new State("<business-logic-stuff>")
104
172
  * // your reactive instances
105
173
  * }, ...middleware);
106
174
  *
107
175
  * // to retreive and work with an individual unit
108
- * const myUnit = AppState.get("<key>"); // Returns State<T>
176
+ * const userState = AppState.get("user"); // Returns State<T>
109
177
  *
110
178
  * // to run a callback anytime a unit of state changes
111
- * const unsubscribe = AppState.subscribe(({ updated }) => {
179
+ * const listener = AppState.subscribe(({ state, updated }) => {
112
180
  * // do something with the `State` instance that updated
181
+ * // the entirety of your state
113
182
  * });
183
+ *
184
+ * // get the current application state
185
+ * const currentState = AppState.getState();
186
+ *
187
+ * // operate on an instance of state
188
+ * AppState.update("user", userState => ({
189
+ * ...userState,
190
+ * // your updates
191
+ * }));
114
192
  * ```
115
193
  */
116
194
  export const createGalena = <T extends Record<string, State<any>>>(
package/src/Logger.ts CHANGED
@@ -22,7 +22,7 @@ export class Logger<T = any> extends Middleware {
22
22
  private previousState: T | null = null;
23
23
 
24
24
  override onBeforeUpdate(state: State<T>) {
25
- this.previousState = state.getSnapshot();
25
+ this.previousState = state.getState();
26
26
  }
27
27
 
28
28
  override onUpdate(state: State<T>) {
@@ -40,7 +40,7 @@ export class Logger<T = any> extends Middleware {
40
40
  console.log(
41
41
  " %cNext State ",
42
42
  "color: rgb(17, 118, 249); font-weight: bold",
43
- state.getSnapshot(),
43
+ state.getState(),
44
44
  );
45
45
  }
46
46