@figliolia/galena 2.3.4 → 3.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.
- package/README.md +172 -476
- package/dist/Galena.cjs +102 -0
- package/dist/Galena.d.cts +80 -0
- package/dist/Galena.d.cts.map +1 -0
- package/dist/Galena.d.mts +80 -0
- package/dist/Galena.d.mts.map +1 -0
- package/dist/Galena.mjs +103 -0
- package/dist/Galena.mjs.map +1 -0
- package/dist/GalenaProvider.cjs +50 -0
- package/dist/GalenaProvider.d.cts +35 -0
- package/dist/GalenaProvider.d.cts.map +1 -0
- package/dist/GalenaProvider.d.mts +35 -0
- package/dist/GalenaProvider.d.mts.map +1 -0
- package/dist/GalenaProvider.mjs +52 -0
- package/dist/GalenaProvider.mjs.map +1 -0
- package/dist/Logger.cjs +46 -0
- package/dist/Logger.d.cts +35 -0
- package/dist/Logger.d.cts.map +1 -0
- package/dist/Logger.d.mts +35 -0
- package/dist/Logger.d.mts.map +1 -0
- package/dist/Logger.mjs +48 -0
- package/dist/Logger.mjs.map +1 -0
- package/dist/Middleware.cjs +62 -0
- package/dist/Middleware.d.cts +65 -0
- package/dist/Middleware.d.cts.map +1 -0
- package/dist/Middleware.d.mts +65 -0
- package/dist/Middleware.d.mts.map +1 -0
- package/dist/Middleware.mjs +64 -0
- package/dist/Middleware.mjs.map +1 -0
- package/dist/Profiler.cjs +41 -0
- package/dist/Profiler.d.cts +31 -0
- package/dist/Profiler.d.cts.map +1 -0
- package/dist/Profiler.d.mts +31 -0
- package/dist/Profiler.d.mts.map +1 -0
- package/dist/Profiler.mjs +43 -0
- package/dist/Profiler.mjs.map +1 -0
- package/dist/State.cjs +147 -0
- package/dist/State.d.cts +114 -0
- package/dist/State.d.cts.map +1 -0
- package/dist/State.d.mts +114 -0
- package/dist/State.d.mts.map +1 -0
- package/dist/State.mjs +148 -0
- package/dist/State.mjs.map +1 -0
- package/dist/commonHooks.cjs +17 -0
- package/dist/commonHooks.mjs +18 -0
- package/dist/commonHooks.mjs.map +1 -0
- package/dist/connect-multi.cjs +42 -0
- package/dist/connect-multi.d.cts +10 -0
- package/dist/connect-multi.d.cts.map +1 -0
- package/dist/connect-multi.d.mts +10 -0
- package/dist/connect-multi.d.mts.map +1 -0
- package/dist/connect-multi.mjs +44 -0
- package/dist/connect-multi.mjs.map +1 -0
- package/dist/connect.cjs +41 -0
- package/dist/connect.d.cts +9 -0
- package/dist/connect.d.cts.map +1 -0
- package/dist/connect.d.mts +9 -0
- package/dist/connect.d.mts.map +1 -0
- package/dist/connect.mjs +43 -0
- package/dist/connect.mjs.map +1 -0
- package/dist/createUseState.cjs +47 -0
- package/dist/createUseState.d.cts +46 -0
- package/dist/createUseState.d.cts.map +1 -0
- package/dist/createUseState.d.mts +46 -0
- package/dist/createUseState.d.mts.map +1 -0
- package/dist/createUseState.mjs +49 -0
- package/dist/createUseState.mjs.map +1 -0
- package/dist/index.cjs +23 -0
- package/dist/index.d.cts +12 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.mjs +11 -0
- package/dist/types.d.cts +23 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +23 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/useState.cjs +45 -0
- package/dist/useState.d.cts +43 -0
- package/dist/useState.d.cts.map +1 -0
- package/dist/useState.d.mts +43 -0
- package/dist/useState.d.mts.map +1 -0
- package/dist/useState.mjs +47 -0
- package/dist/useState.mjs.map +1 -0
- package/media/Logging.png +0 -0
- package/media/Profiling.png +0 -0
- package/package.json +38 -59
- package/src/Galena.ts +120 -0
- package/src/{Middlewares/Logger.ts → Logger.ts} +15 -14
- package/src/Middleware.ts +62 -0
- package/src/Profiler.ts +53 -0
- package/src/State.ts +167 -0
- package/src/index.ts +6 -3
- package/src/types.ts +28 -0
- package/dist/cjs/Galena/Galena.js +0 -223
- package/dist/cjs/Galena/Guards.js +0 -40
- package/dist/cjs/Galena/Scheduler.js +0 -84
- package/dist/cjs/Galena/State.js +0 -314
- package/dist/cjs/Galena/index.js +0 -22
- package/dist/cjs/Galena/types.js +0 -9
- package/dist/cjs/Middleware/Middleware.js +0 -46
- package/dist/cjs/Middleware/index.js +0 -20
- package/dist/cjs/Middleware/types.js +0 -8
- package/dist/cjs/Middlewares/Logger.js +0 -51
- package/dist/cjs/Middlewares/Profiler.js +0 -38
- package/dist/cjs/Middlewares/index.js +0 -7
- package/dist/cjs/index.js +0 -19
- package/dist/cjs/package.json +0 -3
- package/dist/mjs/Galena/Galena.js +0 -218
- package/dist/mjs/Galena/Guards.js +0 -36
- package/dist/mjs/Galena/Scheduler.js +0 -79
- package/dist/mjs/Galena/State.js +0 -313
- package/dist/mjs/Galena/index.js +0 -3
- package/dist/mjs/Galena/types.js +0 -6
- package/dist/mjs/Middleware/Middleware.js +0 -42
- package/dist/mjs/Middleware/index.js +0 -2
- package/dist/mjs/Middleware/types.js +0 -5
- package/dist/mjs/Middlewares/Logger.js +0 -44
- package/dist/mjs/Middlewares/Profiler.js +0 -35
- package/dist/mjs/Middlewares/index.js +0 -2
- package/dist/mjs/index.js +0 -3
- package/dist/mjs/package.json +0 -4
- package/dist/types/Galena/Galena.d.ts +0 -160
- package/dist/types/Galena/Guards.d.ts +0 -29
- package/dist/types/Galena/Scheduler.d.ts +0 -51
- package/dist/types/Galena/State.d.ts +0 -235
- package/dist/types/Galena/index.d.ts +0 -3
- package/dist/types/Galena/types.d.ts +0 -13
- package/dist/types/Middleware/Middleware.d.ts +0 -43
- package/dist/types/Middleware/index.d.ts +0 -2
- package/dist/types/Middleware/types.d.ts +0 -4
- package/dist/types/Middlewares/Logger.d.ts +0 -27
- package/dist/types/Middlewares/Profiler.d.ts +0 -22
- package/dist/types/Middlewares/index.d.ts +0 -2
- package/dist/types/index.d.ts +0 -3
- package/src/Galena/Galena.ts +0 -252
- package/src/Galena/Guards.ts +0 -49
- package/src/Galena/Scheduler.ts +0 -85
- package/src/Galena/State.ts +0 -344
- package/src/Galena/index.ts +0 -3
- package/src/Galena/types.ts +0 -18
- package/src/Middleware/Middleware.ts +0 -45
- package/src/Middleware/index.ts +0 -2
- package/src/Middleware/types.ts +0 -4
- package/src/Middlewares/Profiler.ts +0 -41
- package/src/Middlewares/index.ts +0 -2
package/dist/State.d.cts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Middleware } from "./Middleware.cjs";
|
|
2
|
+
import { NonFunction, Setter, Subscriber } from "./types.cjs";
|
|
3
|
+
|
|
4
|
+
//#region src/State.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* State
|
|
7
|
+
*
|
|
8
|
+
* The unit of reactivity for Galena. `State`'s can act
|
|
9
|
+
* as isolated instances or be part of your global app
|
|
10
|
+
* state (via `Galena` instances).
|
|
11
|
+
*
|
|
12
|
+
* There are three ways to create state instances
|
|
13
|
+
*
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { State, createState, useState, Profiler } from "@figliolia/galena";
|
|
16
|
+
* // for island states that can be shared between react components
|
|
17
|
+
* const myState = new State("<any value>", ...middleware);
|
|
18
|
+
* // or
|
|
19
|
+
* const myState = createState("<any value>", ...middleware);
|
|
20
|
+
*
|
|
21
|
+
* myState.set("<new-value>");
|
|
22
|
+
* myState.update(previousValue => "<new-value>");
|
|
23
|
+
* myState.subscribe(nextValue => {});
|
|
24
|
+
* 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
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
declare class State<T> {
|
|
39
|
+
readonly initialState: NonFunction<T>;
|
|
40
|
+
private state;
|
|
41
|
+
readonly middleware: Middleware<T>[];
|
|
42
|
+
private readonly Emitter;
|
|
43
|
+
constructor(initialState: NonFunction<T>, ...middleware: Middleware<T>[]);
|
|
44
|
+
/**
|
|
45
|
+
* Set
|
|
46
|
+
*
|
|
47
|
+
* Updates the current value of state notifying
|
|
48
|
+
* all interested parties
|
|
49
|
+
*/
|
|
50
|
+
readonly set: (state: NonFunction<T>) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Update
|
|
53
|
+
*
|
|
54
|
+
* Updates the current value of state using a setter function
|
|
55
|
+
* receiving the previous state as a parameter. Notifies all
|
|
56
|
+
* interested parties
|
|
57
|
+
*/
|
|
58
|
+
readonly update: (setter: Setter<T>) => void;
|
|
59
|
+
/**
|
|
60
|
+
* Reset
|
|
61
|
+
*
|
|
62
|
+
* Resets the current state back to the state which the instance
|
|
63
|
+
* was initialized with. Notifies all interested parties
|
|
64
|
+
*/
|
|
65
|
+
readonly reset: () => void;
|
|
66
|
+
/**
|
|
67
|
+
* Get Snapshot
|
|
68
|
+
*
|
|
69
|
+
* Returns the current state. Designed for compatibility with
|
|
70
|
+
* `useSyncExternalStore`
|
|
71
|
+
*/
|
|
72
|
+
readonly getSnapshot: () => NonFunction<T>;
|
|
73
|
+
/**
|
|
74
|
+
* Subscribe
|
|
75
|
+
*
|
|
76
|
+
* Registers a callback to be executed each time state
|
|
77
|
+
* changes. Returns an `unsubscribe` function
|
|
78
|
+
*/
|
|
79
|
+
readonly subscribe: (fn: Subscriber<T>) => () => void;
|
|
80
|
+
/**
|
|
81
|
+
* Register Middleware
|
|
82
|
+
*
|
|
83
|
+
* Registers any number of `Middleware` instances on the
|
|
84
|
+
* current instance of `State`. Your middleware will begin
|
|
85
|
+
* executing at the next state transition
|
|
86
|
+
*/
|
|
87
|
+
registerMiddleware(...middleware: Middleware<T>[]): void;
|
|
88
|
+
private withEmission;
|
|
89
|
+
private emit;
|
|
90
|
+
protected diffSetter(setter: Setter<T>): setter is NonFunction<T>;
|
|
91
|
+
private invokeMiddleware;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Create State
|
|
95
|
+
*
|
|
96
|
+
* Returns the unit of reactivity for Galena. `State`'s can act
|
|
97
|
+
* as isolated instances or be part of your global app
|
|
98
|
+
* state (via `Galena` instances);
|
|
99
|
+
*
|
|
100
|
+
* ```typescript
|
|
101
|
+
* import { createState, Profiler } from "@figliolia/galena";
|
|
102
|
+
*
|
|
103
|
+
* const myState = createState("<any value>", ...middleware);
|
|
104
|
+
*
|
|
105
|
+
* myState.set("<new-value>");
|
|
106
|
+
* myState.update(previousValue => "<new-value>");
|
|
107
|
+
* myState.subscribe(nextValue => {});
|
|
108
|
+
* myState.registerMiddleware(new Profiler());
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
declare function createState<T>(...args: ConstructorParameters<typeof State<T>>): State<T>;
|
|
112
|
+
//#endregion
|
|
113
|
+
export { State, createState };
|
|
114
|
+
//# sourceMappingURL=State.d.cts.map
|
|
@@ -0,0 +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"}
|
package/dist/State.d.mts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Middleware } from "./Middleware.mjs";
|
|
2
|
+
import { NonFunction, Setter, Subscriber } from "./types.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/State.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* State
|
|
7
|
+
*
|
|
8
|
+
* The unit of reactivity for Galena. `State`'s can act
|
|
9
|
+
* as isolated instances or be part of your global app
|
|
10
|
+
* state (via `Galena` instances).
|
|
11
|
+
*
|
|
12
|
+
* There are three ways to create state instances
|
|
13
|
+
*
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { State, createState, useState, Profiler } from "@figliolia/galena";
|
|
16
|
+
* // for island states that can be shared between react components
|
|
17
|
+
* const myState = new State("<any value>", ...middleware);
|
|
18
|
+
* // or
|
|
19
|
+
* const myState = createState("<any value>", ...middleware);
|
|
20
|
+
*
|
|
21
|
+
* myState.set("<new-value>");
|
|
22
|
+
* myState.update(previousValue => "<new-value>");
|
|
23
|
+
* myState.subscribe(nextValue => {});
|
|
24
|
+
* 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
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
declare class State<T> {
|
|
39
|
+
readonly initialState: NonFunction<T>;
|
|
40
|
+
private state;
|
|
41
|
+
readonly middleware: Middleware<T>[];
|
|
42
|
+
private readonly Emitter;
|
|
43
|
+
constructor(initialState: NonFunction<T>, ...middleware: Middleware<T>[]);
|
|
44
|
+
/**
|
|
45
|
+
* Set
|
|
46
|
+
*
|
|
47
|
+
* Updates the current value of state notifying
|
|
48
|
+
* all interested parties
|
|
49
|
+
*/
|
|
50
|
+
readonly set: (state: NonFunction<T>) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Update
|
|
53
|
+
*
|
|
54
|
+
* Updates the current value of state using a setter function
|
|
55
|
+
* receiving the previous state as a parameter. Notifies all
|
|
56
|
+
* interested parties
|
|
57
|
+
*/
|
|
58
|
+
readonly update: (setter: Setter<T>) => void;
|
|
59
|
+
/**
|
|
60
|
+
* Reset
|
|
61
|
+
*
|
|
62
|
+
* Resets the current state back to the state which the instance
|
|
63
|
+
* was initialized with. Notifies all interested parties
|
|
64
|
+
*/
|
|
65
|
+
readonly reset: () => void;
|
|
66
|
+
/**
|
|
67
|
+
* Get Snapshot
|
|
68
|
+
*
|
|
69
|
+
* Returns the current state. Designed for compatibility with
|
|
70
|
+
* `useSyncExternalStore`
|
|
71
|
+
*/
|
|
72
|
+
readonly getSnapshot: () => NonFunction<T>;
|
|
73
|
+
/**
|
|
74
|
+
* Subscribe
|
|
75
|
+
*
|
|
76
|
+
* Registers a callback to be executed each time state
|
|
77
|
+
* changes. Returns an `unsubscribe` function
|
|
78
|
+
*/
|
|
79
|
+
readonly subscribe: (fn: Subscriber<T>) => () => void;
|
|
80
|
+
/**
|
|
81
|
+
* Register Middleware
|
|
82
|
+
*
|
|
83
|
+
* Registers any number of `Middleware` instances on the
|
|
84
|
+
* current instance of `State`. Your middleware will begin
|
|
85
|
+
* executing at the next state transition
|
|
86
|
+
*/
|
|
87
|
+
registerMiddleware(...middleware: Middleware<T>[]): void;
|
|
88
|
+
private withEmission;
|
|
89
|
+
private emit;
|
|
90
|
+
protected diffSetter(setter: Setter<T>): setter is NonFunction<T>;
|
|
91
|
+
private invokeMiddleware;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Create State
|
|
95
|
+
*
|
|
96
|
+
* Returns the unit of reactivity for Galena. `State`'s can act
|
|
97
|
+
* as isolated instances or be part of your global app
|
|
98
|
+
* state (via `Galena` instances);
|
|
99
|
+
*
|
|
100
|
+
* ```typescript
|
|
101
|
+
* import { createState, Profiler } from "@figliolia/galena";
|
|
102
|
+
*
|
|
103
|
+
* const myState = createState("<any value>", ...middleware);
|
|
104
|
+
*
|
|
105
|
+
* myState.set("<new-value>");
|
|
106
|
+
* myState.update(previousValue => "<new-value>");
|
|
107
|
+
* myState.subscribe(nextValue => {});
|
|
108
|
+
* myState.registerMiddleware(new Profiler());
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
declare function createState<T>(...args: ConstructorParameters<typeof State<T>>): State<T>;
|
|
112
|
+
//#endregion
|
|
113
|
+
export { State, createState };
|
|
114
|
+
//# sourceMappingURL=State.d.mts.map
|
|
@@ -0,0 +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"}
|
package/dist/State.mjs
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { EventEmitter } from "@figliolia/event-emitter";
|
|
2
|
+
//#region src/State.ts
|
|
3
|
+
/**
|
|
4
|
+
* State
|
|
5
|
+
*
|
|
6
|
+
* The unit of reactivity for Galena. `State`'s can act
|
|
7
|
+
* as isolated instances or be part of your global app
|
|
8
|
+
* state (via `Galena` instances).
|
|
9
|
+
*
|
|
10
|
+
* There are three ways to create state instances
|
|
11
|
+
*
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { State, createState, useState, Profiler } from "@figliolia/galena";
|
|
14
|
+
* // for island states that can be shared between react components
|
|
15
|
+
* const myState = new State("<any value>", ...middleware);
|
|
16
|
+
* // or
|
|
17
|
+
* const myState = createState("<any value>", ...middleware);
|
|
18
|
+
*
|
|
19
|
+
* myState.set("<new-value>");
|
|
20
|
+
* myState.update(previousValue => "<new-value>");
|
|
21
|
+
* myState.subscribe(nextValue => {});
|
|
22
|
+
* 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
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
var State = class {
|
|
37
|
+
state;
|
|
38
|
+
middleware = [];
|
|
39
|
+
Emitter = new EventEmitter();
|
|
40
|
+
constructor(initialState, ...middleware) {
|
|
41
|
+
this.initialState = initialState;
|
|
42
|
+
this.state = initialState;
|
|
43
|
+
this.registerMiddleware(...middleware);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Set
|
|
47
|
+
*
|
|
48
|
+
* Updates the current value of state notifying
|
|
49
|
+
* all interested parties
|
|
50
|
+
*/
|
|
51
|
+
set = this.withEmission((state) => state);
|
|
52
|
+
/**
|
|
53
|
+
* Update
|
|
54
|
+
*
|
|
55
|
+
* Updates the current value of state using a setter function
|
|
56
|
+
* receiving the previous state as a parameter. Notifies all
|
|
57
|
+
* interested parties
|
|
58
|
+
*/
|
|
59
|
+
update = this.withEmission((setter) => {
|
|
60
|
+
if (this.diffSetter(setter)) return setter;
|
|
61
|
+
return setter(this.state);
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Reset
|
|
65
|
+
*
|
|
66
|
+
* Resets the current state back to the state which the instance
|
|
67
|
+
* was initialized with. Notifies all interested parties
|
|
68
|
+
*/
|
|
69
|
+
reset = this.withEmission(() => this.initialState);
|
|
70
|
+
/**
|
|
71
|
+
* Get Snapshot
|
|
72
|
+
*
|
|
73
|
+
* Returns the current state. Designed for compatibility with
|
|
74
|
+
* `useSyncExternalStore`
|
|
75
|
+
*/
|
|
76
|
+
getSnapshot = () => {
|
|
77
|
+
return this.state;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Subscribe
|
|
81
|
+
*
|
|
82
|
+
* Registers a callback to be executed each time state
|
|
83
|
+
* changes. Returns an `unsubscribe` function
|
|
84
|
+
*/
|
|
85
|
+
subscribe = (fn) => {
|
|
86
|
+
const ID = this.Emitter.on("change", fn);
|
|
87
|
+
return () => {
|
|
88
|
+
this.Emitter.off("change", ID);
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Register Middleware
|
|
93
|
+
*
|
|
94
|
+
* Registers any number of `Middleware` instances on the
|
|
95
|
+
* current instance of `State`. Your middleware will begin
|
|
96
|
+
* executing at the next state transition
|
|
97
|
+
*/
|
|
98
|
+
registerMiddleware(...middleware) {
|
|
99
|
+
this.middleware.push(...middleware);
|
|
100
|
+
}
|
|
101
|
+
withEmission(fn) {
|
|
102
|
+
return (...args) => {
|
|
103
|
+
const result = fn(...args);
|
|
104
|
+
if (result instanceof Promise) {
|
|
105
|
+
result.then((resolved) => this.emit(resolved));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
return this.emit(result);
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
emit(nextState) {
|
|
112
|
+
this.invokeMiddleware("onBeforeUpdate");
|
|
113
|
+
this.state = nextState;
|
|
114
|
+
this.Emitter.emit("change", this.state);
|
|
115
|
+
this.invokeMiddleware("onUpdate");
|
|
116
|
+
}
|
|
117
|
+
diffSetter(setter) {
|
|
118
|
+
return typeof setter !== "function";
|
|
119
|
+
}
|
|
120
|
+
invokeMiddleware(fn) {
|
|
121
|
+
for (const middleware of this.middleware) middleware[fn](this);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Create State
|
|
126
|
+
*
|
|
127
|
+
* Returns the unit of reactivity for Galena. `State`'s can act
|
|
128
|
+
* as isolated instances or be part of your global app
|
|
129
|
+
* state (via `Galena` instances);
|
|
130
|
+
*
|
|
131
|
+
* ```typescript
|
|
132
|
+
* import { createState, Profiler } from "@figliolia/galena";
|
|
133
|
+
*
|
|
134
|
+
* const myState = createState("<any value>", ...middleware);
|
|
135
|
+
*
|
|
136
|
+
* myState.set("<new-value>");
|
|
137
|
+
* myState.update(previousValue => "<new-value>");
|
|
138
|
+
* myState.subscribe(nextValue => {});
|
|
139
|
+
* myState.registerMiddleware(new Profiler());
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
function createState(...args) {
|
|
143
|
+
return new State(...args);
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
146
|
+
export { State, createState };
|
|
147
|
+
|
|
148
|
+
//# sourceMappingURL=State.mjs.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
let react = require("react");
|
|
2
|
+
//#region src/commonHooks.ts
|
|
3
|
+
function useStableSelector(selector) {
|
|
4
|
+
const stableSelector = (0, react.useRef)(selector);
|
|
5
|
+
(0, react.useEffect)(() => {
|
|
6
|
+
stableSelector.current = ((...args) => selector(...args));
|
|
7
|
+
}, [selector]);
|
|
8
|
+
return stableSelector;
|
|
9
|
+
}
|
|
10
|
+
function useStateHookAPI(value, selector) {
|
|
11
|
+
const state = (0, react.useSyncExternalStore)(value.subscribe, value.getSnapshot);
|
|
12
|
+
const selectedValue = (0, react.useMemo)(() => selector.current(state), [state, selector]);
|
|
13
|
+
return (0, react.useMemo)(() => [selectedValue, value.update], [selectedValue, value]);
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
exports.useStableSelector = useStableSelector;
|
|
17
|
+
exports.useStateHookAPI = useStateHookAPI;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef, useSyncExternalStore } from "react";
|
|
2
|
+
//#region src/commonHooks.ts
|
|
3
|
+
function useStableSelector(selector) {
|
|
4
|
+
const stableSelector = useRef(selector);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
stableSelector.current = ((...args) => selector(...args));
|
|
7
|
+
}, [selector]);
|
|
8
|
+
return stableSelector;
|
|
9
|
+
}
|
|
10
|
+
function useStateHookAPI(value, selector) {
|
|
11
|
+
const state = useSyncExternalStore(value.subscribe, value.getSnapshot);
|
|
12
|
+
const selectedValue = useMemo(() => selector.current(state), [state, selector]);
|
|
13
|
+
return useMemo(() => [selectedValue, value.update], [selectedValue, value]);
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { useStableSelector, useStateHookAPI };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=commonHooks.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commonHooks.mjs","names":[],"sources":["../src/commonHooks.ts"],"sourcesContent":["import {\n type RefObject,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport type { State } from \"./State\";\nimport type { NonFunction } from \"./types\";\n\nexport function useStableSelector<F extends (...args: any[]) => any>(\n selector: F,\n) {\n const stableSelector = useRef(selector);\n\n useEffect(() => {\n stableSelector.current = ((...args: Parameters<typeof selector>) =>\n selector(...args)) as F;\n }, [selector]);\n\n return stableSelector;\n}\n\nexport function useStateHookAPI<T, U>(\n value: State<T>,\n selector: RefObject<(state: NonFunction<T>) => U>,\n) {\n const state = useSyncExternalStore(value.subscribe, value.getSnapshot);\n const selectedValue = useMemo(\n () => selector.current(state),\n [state, selector],\n );\n return useMemo(\n () => [selectedValue, value.update] as const,\n [selectedValue, value],\n );\n}\n"],"mappings":";;AAUA,SAAgB,kBACd,UACA;CACA,MAAM,iBAAiB,OAAO,SAAS;AAEvC,iBAAgB;AACd,iBAAe,YAAY,GAAG,SAC5B,SAAS,GAAG,KAAK;IAClB,CAAC,SAAS,CAAC;AAEd,QAAO;;AAGT,SAAgB,gBACd,OACA,UACA;CACA,MAAM,QAAQ,qBAAqB,MAAM,WAAW,MAAM,YAAY;CACtE,MAAM,gBAAgB,cACd,SAAS,QAAQ,MAAM,EAC7B,CAAC,OAAO,SAAS,CAClB;AACD,QAAO,cACC,CAAC,eAAe,MAAM,OAAO,EACnC,CAAC,eAAe,MAAM,CACvB"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
let react = require("react");
|
|
2
|
+
//#region src/connect-multi.tsx
|
|
3
|
+
const connectMulti = (...states) => {
|
|
4
|
+
return (selector) => {
|
|
5
|
+
return (WrappedComponent) => {
|
|
6
|
+
return class GalenaMultiComponent extends react.Component {
|
|
7
|
+
state;
|
|
8
|
+
listeners = [];
|
|
9
|
+
constructor(props) {
|
|
10
|
+
super(props);
|
|
11
|
+
this.state = this.computeSelector();
|
|
12
|
+
}
|
|
13
|
+
static displayName = `GalenaMultiComponent(${WrappedComponent.displayName ?? WrappedComponent.name ?? "Component"})`;
|
|
14
|
+
componentDidMount() {
|
|
15
|
+
this.listeners = this.bindListeners();
|
|
16
|
+
}
|
|
17
|
+
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
18
|
+
if (nextProps !== this.props) this.setState(this.computeSelector(nextProps));
|
|
19
|
+
}
|
|
20
|
+
shouldComponentUpdate(nextProps, nextState) {
|
|
21
|
+
return nextState !== this.state || nextProps !== this.props;
|
|
22
|
+
}
|
|
23
|
+
componentWillUnmount() {
|
|
24
|
+
while (this.listeners.length) this.listeners.pop()?.();
|
|
25
|
+
}
|
|
26
|
+
bindListeners() {
|
|
27
|
+
return states.map((state) => {
|
|
28
|
+
return state.subscribe(() => this.setState(this.computeSelector()));
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
computeSelector(props = this.props) {
|
|
32
|
+
return selector(states.map((s) => s.getSnapshot()), props);
|
|
33
|
+
}
|
|
34
|
+
render() {
|
|
35
|
+
return <WrappedComponent {...this.props} {...this.state} />;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
42
|
+
exports.connectMulti = connectMulti;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DerivedSelector, Subtract } from "./types.cjs";
|
|
2
|
+
import { State } from "./State.cjs";
|
|
3
|
+
import { ComponentType } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/connect-multi.d.ts
|
|
6
|
+
declare const connectMulti: <StateInstances extends State<any>[]>(...states: StateInstances) => <Selector extends DerivedSelector<StateInstances>>(selector: Selector) => <ComponentProps extends ReturnType<Selector>>(WrappedComponent: ComponentType<ComponentProps>) => ComponentType<Subtract<ComponentProps, ReturnType<Selector>>>;
|
|
7
|
+
type ReactiveStates<T extends ReturnType<typeof connectMulti>> = Parameters<Parameters<T>[0]>[0];
|
|
8
|
+
//#endregion
|
|
9
|
+
export { ReactiveStates, connectMulti };
|
|
10
|
+
//# sourceMappingURL=connect-multi.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect-multi.d.cts","names":[],"sources":["../src/connect-multi.tsx"],"mappings":";;;;;cAIa,YAAA,0BAAuC,KAAA,YAC/C,MAAA,EAAQ,cAAA,uBAEc,eAAA,CAAgB,cAAA,GACvC,QAAA,EAAU,QAAA,6BAEqB,UAAA,CAAW,QAAA,GACxC,gBAAA,EAAkB,aAAA,CAAc,cAAA,MAC/B,aAAA,CAAc,QAAA,CAAS,cAAA,EAAgB,UAAA,CAAW,QAAA;AAAA,KA+D7C,cAAA,WAAyB,UAAA,QAAkB,YAAA,KACrD,UAAA,CAAW,UAAA,CAAW,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DerivedSelector, Subtract } from "./types.mjs";
|
|
2
|
+
import { State } from "./State.mjs";
|
|
3
|
+
import { ComponentType } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/connect-multi.d.ts
|
|
6
|
+
declare const connectMulti: <StateInstances extends State<any>[]>(...states: StateInstances) => <Selector extends DerivedSelector<StateInstances>>(selector: Selector) => <ComponentProps extends ReturnType<Selector>>(WrappedComponent: ComponentType<ComponentProps>) => ComponentType<Subtract<ComponentProps, ReturnType<Selector>>>;
|
|
7
|
+
type ReactiveStates<T extends ReturnType<typeof connectMulti>> = Parameters<Parameters<T>[0]>[0];
|
|
8
|
+
//#endregion
|
|
9
|
+
export { ReactiveStates, connectMulti };
|
|
10
|
+
//# sourceMappingURL=connect-multi.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect-multi.d.mts","names":[],"sources":["../src/connect-multi.tsx"],"mappings":";;;;;cAIa,YAAA,0BAAuC,KAAA,YAC/C,MAAA,EAAQ,cAAA,uBAEc,eAAA,CAAgB,cAAA,GACvC,QAAA,EAAU,QAAA,6BAEqB,UAAA,CAAW,QAAA,GACxC,gBAAA,EAAkB,aAAA,CAAc,cAAA,MAC/B,aAAA,CAAc,QAAA,CAAS,cAAA,EAAgB,UAAA,CAAW,QAAA;AAAA,KA+D7C,cAAA,WAAyB,UAAA,QAAkB,YAAA,KACrD,UAAA,CAAW,UAAA,CAAW,CAAA"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Component } from "react";
|
|
2
|
+
//#region src/connect-multi.tsx
|
|
3
|
+
const connectMulti = (...states) => {
|
|
4
|
+
return (selector) => {
|
|
5
|
+
return (WrappedComponent) => {
|
|
6
|
+
return class GalenaMultiComponent extends Component {
|
|
7
|
+
state;
|
|
8
|
+
listeners = [];
|
|
9
|
+
constructor(props) {
|
|
10
|
+
super(props);
|
|
11
|
+
this.state = this.computeSelector();
|
|
12
|
+
}
|
|
13
|
+
static displayName = `GalenaMultiComponent(${WrappedComponent.displayName ?? WrappedComponent.name ?? "Component"})`;
|
|
14
|
+
componentDidMount() {
|
|
15
|
+
this.listeners = this.bindListeners();
|
|
16
|
+
}
|
|
17
|
+
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
18
|
+
if (nextProps !== this.props) this.setState(this.computeSelector(nextProps));
|
|
19
|
+
}
|
|
20
|
+
shouldComponentUpdate(nextProps, nextState) {
|
|
21
|
+
return nextState !== this.state || nextProps !== this.props;
|
|
22
|
+
}
|
|
23
|
+
componentWillUnmount() {
|
|
24
|
+
while (this.listeners.length) this.listeners.pop()?.();
|
|
25
|
+
}
|
|
26
|
+
bindListeners() {
|
|
27
|
+
return states.map((state) => {
|
|
28
|
+
return state.subscribe(() => this.setState(this.computeSelector()));
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
computeSelector(props = this.props) {
|
|
32
|
+
return selector(states.map((s) => s.getSnapshot()), props);
|
|
33
|
+
}
|
|
34
|
+
render() {
|
|
35
|
+
return <WrappedComponent {...this.props} {...this.state} />;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
42
|
+
export { connectMulti };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=connect-multi.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect-multi.mjs","names":[],"sources":["../src/connect-multi.tsx"],"sourcesContent":["import { Component, type ComponentType } from \"react\";\nimport type { State } from \"./State\";\nimport type { DerivedArguments, DerivedSelector, Subtract } from \"./types\";\n\nexport const connectMulti = <StateInstances extends State<any>[]>(\n ...states: StateInstances\n) => {\n return <Selector extends DerivedSelector<StateInstances>>(\n selector: Selector,\n ) => {\n return <ComponentProps extends ReturnType<Selector>>(\n WrappedComponent: ComponentType<ComponentProps>,\n ): ComponentType<Subtract<ComponentProps, ReturnType<Selector>>> => {\n type OwnProps = Subtract<ComponentProps, ReturnType<Selector>>;\n return class GalenaMultiComponent extends Component<\n OwnProps,\n ReturnType<Selector>\n > {\n override state: any;\n listeners: (() => void)[] = [];\n constructor(props: OwnProps) {\n super(props);\n this.state = this.computeSelector();\n }\n\n static displayName = `GalenaMultiComponent(${\n WrappedComponent.displayName ?? WrappedComponent.name ?? \"Component\"\n })`;\n\n public override componentDidMount() {\n this.listeners = this.bindListeners();\n }\n\n public override UNSAFE_componentWillReceiveProps(nextProps: OwnProps) {\n if (nextProps !== this.props) {\n this.setState(this.computeSelector(nextProps));\n }\n }\n\n public override shouldComponentUpdate(\n nextProps: OwnProps,\n nextState: ReturnType<Selector>,\n ) {\n return nextState !== this.state || nextProps !== this.props;\n }\n\n public override componentWillUnmount() {\n while (this.listeners.length) {\n this.listeners.pop()?.();\n }\n }\n\n private bindListeners() {\n return states.map(state => {\n return state.subscribe(() => this.setState(this.computeSelector()));\n });\n }\n\n private computeSelector(props: OwnProps = this.props) {\n return selector(\n states.map(s =>\n s.getSnapshot(),\n ) as DerivedArguments<StateInstances>,\n props,\n );\n }\n\n public override render() {\n return <WrappedComponent {...this.props} {...this.state} />;\n }\n };\n };\n };\n};\n\nexport type ReactiveStates<T extends ReturnType<typeof connectMulti>> =\n Parameters<Parameters<T>[0]>[0];\n"],"mappings":";;AAIA,MAAa,gBACX,GAAG,WACA;AACH,SACE,aACG;AACH,UACE,qBACkE;AAElE,UAAO,MAAM,6BAA6B,UAGxC;IACA;IACA,YAA4B,EAAE;IAC9B,YAAY,OAAiB;AAC3B,WAAM,MAAM;AACZ,UAAK,QAAQ,KAAK,iBAAiB;;IAGrC,OAAO,cAAc,wBACnB,iBAAiB,eAAe,iBAAiB,QAAQ,YAC1D;IAED,oBAAoC;AAClC,UAAK,YAAY,KAAK,eAAe;;IAGvC,iCAAiD,WAAqB;AACpE,SAAI,cAAc,KAAK,MACrB,MAAK,SAAS,KAAK,gBAAgB,UAAU,CAAC;;IAIlD,sBACE,WACA,WACA;AACA,YAAO,cAAc,KAAK,SAAS,cAAc,KAAK;;IAGxD,uBAAuC;AACrC,YAAO,KAAK,UAAU,OACpB,MAAK,UAAU,KAAK,IAAI;;IAI5B,gBAAwB;AACtB,YAAO,OAAO,KAAI,UAAS;AACzB,aAAO,MAAM,gBAAgB,KAAK,SAAS,KAAK,iBAAiB,CAAC,CAAC;OACnE;;IAGJ,gBAAwB,QAAkB,KAAK,OAAO;AACpD,YAAO,SACL,OAAO,KAAI,MACT,EAAE,aAAa,CAChB,EACD,MACD;;IAGH,SAAyB;AACvB,YAAO,CAAC,qBAAqB,KAAK,WAAW,KAAK"}
|
package/dist/connect.cjs
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
let react = require("react");
|
|
2
|
+
//#region src/connect.tsx
|
|
3
|
+
const connect = (state) => {
|
|
4
|
+
return (selection) => {
|
|
5
|
+
return (WrappedComponent) => {
|
|
6
|
+
return class GalenaComponent extends react.Component {
|
|
7
|
+
state;
|
|
8
|
+
listener = null;
|
|
9
|
+
constructor(props) {
|
|
10
|
+
super(props);
|
|
11
|
+
this.update = this.update.bind(this);
|
|
12
|
+
this.state = selection(state.getSnapshot(), this.props);
|
|
13
|
+
}
|
|
14
|
+
static displayName = `GalenaComponent(${(WrappedComponent.displayName ?? WrappedComponent.name) || "Component"})`;
|
|
15
|
+
componentDidMount() {
|
|
16
|
+
this.listener = state.subscribe((state) => this.update(state));
|
|
17
|
+
}
|
|
18
|
+
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
19
|
+
if (nextProps !== this.props) this.update(state.getSnapshot(), nextProps);
|
|
20
|
+
}
|
|
21
|
+
shouldComponentUpdate(nextProps, nextState) {
|
|
22
|
+
return nextState !== this.state || nextProps !== this.props;
|
|
23
|
+
}
|
|
24
|
+
componentWillUnmount() {
|
|
25
|
+
if (this.listener) {
|
|
26
|
+
this.listener();
|
|
27
|
+
this.listener = null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
update(nextState, ownProps = this.props) {
|
|
31
|
+
this.setState(selection(nextState, ownProps));
|
|
32
|
+
}
|
|
33
|
+
render() {
|
|
34
|
+
return <WrappedComponent {...this.props} {...this.state} />;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
//#endregion
|
|
41
|
+
exports.connect = connect;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Subtract } from "./types.cjs";
|
|
2
|
+
import { State } from "./State.cjs";
|
|
3
|
+
import { ComponentType } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/connect.d.ts
|
|
6
|
+
declare const connect: <StateInstance extends State<any>>(state: StateInstance) => <SelectorFunction extends (state: ReturnType<StateInstance["getSnapshot"]>, ownProps: any) => Record<string, any>>(selection: SelectorFunction) => <ComponentProps extends ReturnType<SelectorFunction>>(WrappedComponent: ComponentType<ComponentProps>) => ComponentType<Subtract<ComponentProps, ReturnType<SelectorFunction>>>;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { connect };
|
|
9
|
+
//# sourceMappingURL=connect.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.d.cts","names":[],"sources":["../src/connect.tsx"],"mappings":";;;;;cAIa,OAAA,yBAAiC,KAAA,OAC5C,KAAA,EAAO,aAAA,gCAKH,KAAA,EAAK,UAAA,CAAA,aAAA,kBACL,QAAA,UACG,MAAA,eAEL,SAAA,EAAW,gBAAA,6BAGW,UAAA,CAAA,gBAAA,GACpB,gBAAA,EAAkB,aAAA,CAAc,cAAA,MAC/B,aAAA,CAAc,QAAA,CAAS,cAAA,EAAc,UAAA,CAAA,gBAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Subtract } from "./types.mjs";
|
|
2
|
+
import { State } from "./State.mjs";
|
|
3
|
+
import { ComponentType } from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/connect.d.ts
|
|
6
|
+
declare const connect: <StateInstance extends State<any>>(state: StateInstance) => <SelectorFunction extends (state: ReturnType<StateInstance["getSnapshot"]>, ownProps: any) => Record<string, any>>(selection: SelectorFunction) => <ComponentProps extends ReturnType<SelectorFunction>>(WrappedComponent: ComponentType<ComponentProps>) => ComponentType<Subtract<ComponentProps, ReturnType<SelectorFunction>>>;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { connect };
|
|
9
|
+
//# sourceMappingURL=connect.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.d.mts","names":[],"sources":["../src/connect.tsx"],"mappings":";;;;;cAIa,OAAA,yBAAiC,KAAA,OAC5C,KAAA,EAAO,aAAA,gCAKH,KAAA,EAAK,UAAA,CAAA,aAAA,kBACL,QAAA,UACG,MAAA,eAEL,SAAA,EAAW,gBAAA,6BAGW,UAAA,CAAA,gBAAA,GACpB,gBAAA,EAAkB,aAAA,CAAc,cAAA,MAC/B,aAAA,CAAc,QAAA,CAAS,cAAA,EAAc,UAAA,CAAA,gBAAA"}
|