@slimr/react 3.0.71 → 3.0.74
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/cjs/Observable.js +2 -2
- package/cjs/Observable.js.map +1 -1
- package/cjs/Observable.ts +80 -80
- package/cjs/index.d.ts +1 -1
- package/cjs/index.js +1 -1
- package/cjs/index.js.map +1 -1
- package/cjs/index.ts +1 -1
- package/cjs/observables.d.ts +0 -0
- package/cjs/observables.js +2 -0
- package/cjs/observables.js.map +1 -0
- package/cjs/observables.ts +0 -0
- package/esm/Observable.js +4 -4
- package/esm/Observable.js.map +1 -1
- package/esm/Observable.ts +80 -80
- package/esm/index.d.ts +1 -1
- package/esm/index.js +1 -1
- package/esm/index.js.map +1 -1
- package/esm/index.ts +1 -1
- package/esm/observables.d.ts +1 -0
- package/esm/observables.js +2 -0
- package/esm/observables.js.map +1 -0
- package/esm/observables.ts +0 -0
- package/package.json +6 -6
- package/src/Observable.ts +80 -80
- package/src/index.ts +1 -1
package/cjs/Observable.js
CHANGED
|
@@ -35,10 +35,10 @@ class Observable {
|
|
|
35
35
|
globalThis.observables[name] = this;
|
|
36
36
|
}
|
|
37
37
|
async publish() {
|
|
38
|
-
return Promise.all([...this.subscribers].map(subscriber => subscriber(this._value)));
|
|
38
|
+
return Promise.all([...this.subscribers].map((subscriber) => subscriber(this._value)));
|
|
39
39
|
}
|
|
40
40
|
async set(newValueOrSetter) {
|
|
41
|
-
const newValue = typeof newValueOrSetter ===
|
|
41
|
+
const newValue = typeof newValueOrSetter === "function"
|
|
42
42
|
? newValueOrSetter(this._value)
|
|
43
43
|
: newValueOrSetter;
|
|
44
44
|
if (!(0, util_1.areEqualDeep)(this._value, newValue)) {
|
package/cjs/Observable.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Observable.js","sourceRoot":"","sources":["../src/Observable.ts"],"names":[],"mappings":";AAAA,6EAA6E;;;AAE7E,
|
|
1
|
+
{"version":3,"file":"Observable.js","sourceRoot":"","sources":["../src/Observable.ts"],"names":[],"mappings":";AAAA,6EAA6E;;;AAE7E,sCAA0C;AAC1C,iCAA2C;AAI3C,mBAAmB;AACnB,UAAU,CAAC,WAAW,GAAG,EAAE,CAAA;AAE3B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAa,UAAU;IACtB,IAAI,CAAQ;IACJ,MAAM,CAAG;IACT,WAAW,CAAyB;IAE5C,YAAY,IAAY,EAAE,YAAe;QACxC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,MAAM,GAAG,YAAY,CAAA;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,GAAG,EAAE,CAAA;QAC5B,mBAAmB;QACnB,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,OAAO;QACZ,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACvF,CAAC;IAUD,KAAK,CAAC,GAAG,CAAC,gBAAqB;QAC9B,MAAM,QAAQ,GACb,OAAO,gBAAgB,KAAK,UAAU;YACrC,CAAC,CAAE,gBAAwC,CAAC,IAAI,CAAC,MAAM,CAAC;YACxD,CAAC,CAAC,gBAAgB,CAAA;QACpB,IAAI,CAAC,IAAA,mBAAY,EAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC1C,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAA;YACtB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;QACrB,CAAC;IACF,CAAC;IAED;;;;OAIG;IACH,SAAS,CAAC,EAAsB;QAC/B,+EAA+E;QAC/E,oDAAoD;QACpD,MAAM,SAAS,GAAG,KAAK,EAAE,QAAW,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAA;QACrD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC/B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;IAClC,CAAC;IAED,WAAW,CAAC,EAAsB;QACjC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAC5B,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,GAAG;QACF,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,IAAA,gBAAQ,EAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACxC,IAAA,iBAAS,EAAC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAA;IAC9C,CAAC;IAED,IAAI,GAAG;QACN,2EAA2E;QAC3E,kCAAkC;QAClC,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IACD,IAAI,GAAG,CAAC,QAAW;QAClB,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACnB,CAAC;CACD;AAlFD,gCAkFC"}
|
package/cjs/Observable.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
// this file has exports to create an observable and useObservable react hook
|
|
2
2
|
|
|
3
|
-
import { areEqualDeep } from
|
|
4
|
-
import {
|
|
3
|
+
import { areEqualDeep } from "@slimr/util"
|
|
4
|
+
import { useEffect, useState } from "react"
|
|
5
5
|
|
|
6
|
-
type ObservableSetter<T> = (value: T) => T
|
|
6
|
+
type ObservableSetter<T> = (value: T) => T
|
|
7
7
|
|
|
8
8
|
// @ts-expect-error
|
|
9
|
-
globalThis.observables = {}
|
|
9
|
+
globalThis.observables = {}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Provides a variable with observable capabilities, like pub/sub and React hook integration.
|
|
13
|
-
*
|
|
13
|
+
*
|
|
14
14
|
* @usage
|
|
15
15
|
* ```tsx
|
|
16
16
|
* const myObservable = new Observable('myObservable', 0);
|
|
@@ -18,7 +18,7 @@ globalThis.observables = {};
|
|
|
18
18
|
* setTimeout(() => { myObservable.val = 42; }, 1000);
|
|
19
19
|
* setTimeout(() => { myObservable.set(50); }, 2000);
|
|
20
20
|
* setTimeout(() => { myObservable.set(last => last + 1); }, 1000);
|
|
21
|
-
*
|
|
21
|
+
*
|
|
22
22
|
* function MyComponent() {
|
|
23
23
|
* myObservable.use();
|
|
24
24
|
* return <div>{myObservable.value}</div>;
|
|
@@ -26,85 +26,85 @@ globalThis.observables = {};
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
export class Observable<T> {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
name: string
|
|
30
|
+
private _value: T
|
|
31
|
+
private subscribers: Set<(value: T) => void>
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
constructor(name: string, initialValue: T) {
|
|
34
|
+
this.name = name
|
|
35
|
+
this._value = initialValue
|
|
36
|
+
this.subscribers = new Set()
|
|
37
|
+
// @ts-expect-error
|
|
38
|
+
globalThis.observables[name] = this
|
|
39
|
+
}
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
async publish() {
|
|
42
|
+
return Promise.all([...this.subscribers].map((subscriber) => subscriber(this._value)))
|
|
43
|
+
}
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Sets a new value for the observable and notifies subscribers if the value changed.
|
|
47
|
+
*
|
|
48
|
+
* @param newValueOrSetter - The new value or a function that takes the current value and returns the new value.
|
|
49
|
+
* @returns The new value.
|
|
50
|
+
*/
|
|
51
|
+
async set(setter: ObservableSetter<T>): Promise<void>
|
|
52
|
+
async set(newValue: T): Promise<void>
|
|
53
|
+
async set(newValueOrSetter: any): Promise<void> {
|
|
54
|
+
const newValue =
|
|
55
|
+
typeof newValueOrSetter === "function"
|
|
56
|
+
? (newValueOrSetter as ObservableSetter<T>)(this._value)
|
|
57
|
+
: newValueOrSetter
|
|
58
|
+
if (!areEqualDeep(this._value, newValue)) {
|
|
59
|
+
this._value = newValue
|
|
60
|
+
await this.publish()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Register a callback to be called when the observable value changes.
|
|
66
|
+
* @param cb - The callback to be called when the value changes.
|
|
67
|
+
* @returns
|
|
68
|
+
*/
|
|
69
|
+
subscribe(cb: (value: T) => void): () => void {
|
|
70
|
+
// promisify the callback so it behaves like an async function even if it's not
|
|
71
|
+
// so that we can await all subscribers in publish()
|
|
72
|
+
const cbPromise = async (newValue: T) => cb(newValue)
|
|
73
|
+
this.subscribers.add(cbPromise)
|
|
74
|
+
return () => this.unsubscribe(cb)
|
|
75
|
+
}
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
unsubscribe(cb: (value: T) => void): void {
|
|
78
|
+
this.subscribers.delete(cb)
|
|
79
|
+
}
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
81
|
+
/**
|
|
82
|
+
* A React hook to use this observable in a component
|
|
83
|
+
*
|
|
84
|
+
* It does not return the value, but subscribes to changes and forces re-render
|
|
85
|
+
* when the value changes.
|
|
86
|
+
*
|
|
87
|
+
* @usage
|
|
88
|
+
* ```tsx
|
|
89
|
+
* const myObservable = new Observable('myObservable', 0);
|
|
90
|
+
*
|
|
91
|
+
* function MyComponent() {
|
|
92
|
+
* myObservable.use();
|
|
93
|
+
* return <div>{myObservable.value}</div>;
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
use() {
|
|
98
|
+
const [_, setValue] = useState(this.val)
|
|
99
|
+
useEffect(() => this.subscribe(setValue), [])
|
|
100
|
+
}
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
102
|
+
get val(): T {
|
|
103
|
+
// Freeze the value to avoid cases where the internal object may be mutated
|
|
104
|
+
// without triggering subscribers.
|
|
105
|
+
return Object.freeze(this._value)
|
|
106
|
+
}
|
|
107
|
+
set val(newValue: T) {
|
|
108
|
+
this.set(newValue)
|
|
109
|
+
}
|
|
110
110
|
}
|
package/cjs/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export * from "@slimr/styled";
|
|
|
5
5
|
export * from "@slimr/swr";
|
|
6
6
|
export * from "react-use";
|
|
7
7
|
export * from "./merge-refs.js";
|
|
8
|
+
export * from "./Observable.js";
|
|
8
9
|
export * from "./useColorScheme.js";
|
|
9
10
|
export * from "./useMemos.js";
|
|
10
|
-
export * from "./Observable.js";
|
|
11
11
|
export * from "./useSet2.js";
|
package/cjs/index.js
CHANGED
|
@@ -21,8 +21,8 @@ __exportStar(require("@slimr/styled"), exports);
|
|
|
21
21
|
__exportStar(require("@slimr/swr"), exports);
|
|
22
22
|
__exportStar(require("react-use"), exports);
|
|
23
23
|
__exportStar(require("./merge-refs.js"), exports);
|
|
24
|
+
__exportStar(require("./Observable.js"), exports);
|
|
24
25
|
__exportStar(require("./useColorScheme.js"), exports);
|
|
25
26
|
__exportStar(require("./useMemos.js"), exports);
|
|
26
|
-
__exportStar(require("./Observable.js"), exports);
|
|
27
27
|
__exportStar(require("./useSet2.js"), exports);
|
|
28
28
|
//# sourceMappingURL=index.js.map
|
package/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA4B;AAC5B,kDAA+B;AAC/B,gDAA6B;AAC7B,gDAA6B;AAC7B,6CAA0B;AAC1B,4CAAyB;AAEzB,kDAA+B;AAC/B,sDAAmC;AACnC,gDAA6B;AAC7B
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA4B;AAC5B,kDAA+B;AAC/B,gDAA6B;AAC7B,gDAA6B;AAC7B,6CAA0B;AAC1B,4CAAyB;AAEzB,kDAA+B;AAC/B,kDAA+B;AAC/B,sDAAmC;AACnC,gDAA6B;AAC7B,+CAA4B"}
|
package/cjs/index.ts
CHANGED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observables.js","sourceRoot":"","sources":["../src/observables.ts"],"names":[],"mappings":""}
|
|
File without changes
|
package/esm/Observable.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// this file has exports to create an observable and useObservable react hook
|
|
2
|
-
import { areEqualDeep } from
|
|
3
|
-
import {
|
|
2
|
+
import { areEqualDeep } from "@slimr/util";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
4
|
// @ts-expect-error
|
|
5
5
|
globalThis.observables = {};
|
|
6
6
|
/**
|
|
@@ -32,10 +32,10 @@ export class Observable {
|
|
|
32
32
|
globalThis.observables[name] = this;
|
|
33
33
|
}
|
|
34
34
|
async publish() {
|
|
35
|
-
return Promise.all([...this.subscribers].map(subscriber => subscriber(this._value)));
|
|
35
|
+
return Promise.all([...this.subscribers].map((subscriber) => subscriber(this._value)));
|
|
36
36
|
}
|
|
37
37
|
async set(newValueOrSetter) {
|
|
38
|
-
const newValue = typeof newValueOrSetter ===
|
|
38
|
+
const newValue = typeof newValueOrSetter === "function"
|
|
39
39
|
? newValueOrSetter(this._value)
|
|
40
40
|
: newValueOrSetter;
|
|
41
41
|
if (!areEqualDeep(this._value, newValue)) {
|
package/esm/Observable.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Observable.js","sourceRoot":"","sources":["../src/Observable.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"Observable.js","sourceRoot":"","sources":["../src/Observable.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAI3C,mBAAmB;AACnB,UAAU,CAAC,WAAW,GAAG,EAAE,CAAA;AAE3B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,UAAU;IACtB,IAAI,CAAQ;IACJ,MAAM,CAAG;IACT,WAAW,CAAyB;IAE5C,YAAY,IAAY,EAAE,YAAe;QACxC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,MAAM,GAAG,YAAY,CAAA;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,GAAG,EAAE,CAAA;QAC5B,mBAAmB;QACnB,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,OAAO;QACZ,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACvF,CAAC;IAUD,KAAK,CAAC,GAAG,CAAC,gBAAqB;QAC9B,MAAM,QAAQ,GACb,OAAO,gBAAgB,KAAK,UAAU;YACrC,CAAC,CAAE,gBAAwC,CAAC,IAAI,CAAC,MAAM,CAAC;YACxD,CAAC,CAAC,gBAAgB,CAAA;QACpB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC1C,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAA;YACtB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;QACrB,CAAC;IACF,CAAC;IAED;;;;OAIG;IACH,SAAS,CAAC,EAAsB;QAC/B,+EAA+E;QAC/E,oDAAoD;QACpD,MAAM,SAAS,GAAG,KAAK,EAAE,QAAW,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAA;QACrD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC/B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;IAClC,CAAC;IAED,WAAW,CAAC,EAAsB;QACjC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAC5B,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,GAAG;QACF,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACxC,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAA;IAC9C,CAAC;IAED,IAAI,GAAG;QACN,2EAA2E;QAC3E,kCAAkC;QAClC,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IACD,IAAI,GAAG,CAAC,QAAW;QAClB,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACnB,CAAC;CACD"}
|
package/esm/Observable.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
// this file has exports to create an observable and useObservable react hook
|
|
2
2
|
|
|
3
|
-
import { areEqualDeep } from
|
|
4
|
-
import {
|
|
3
|
+
import { areEqualDeep } from "@slimr/util"
|
|
4
|
+
import { useEffect, useState } from "react"
|
|
5
5
|
|
|
6
|
-
type ObservableSetter<T> = (value: T) => T
|
|
6
|
+
type ObservableSetter<T> = (value: T) => T
|
|
7
7
|
|
|
8
8
|
// @ts-expect-error
|
|
9
|
-
globalThis.observables = {}
|
|
9
|
+
globalThis.observables = {}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Provides a variable with observable capabilities, like pub/sub and React hook integration.
|
|
13
|
-
*
|
|
13
|
+
*
|
|
14
14
|
* @usage
|
|
15
15
|
* ```tsx
|
|
16
16
|
* const myObservable = new Observable('myObservable', 0);
|
|
@@ -18,7 +18,7 @@ globalThis.observables = {};
|
|
|
18
18
|
* setTimeout(() => { myObservable.val = 42; }, 1000);
|
|
19
19
|
* setTimeout(() => { myObservable.set(50); }, 2000);
|
|
20
20
|
* setTimeout(() => { myObservable.set(last => last + 1); }, 1000);
|
|
21
|
-
*
|
|
21
|
+
*
|
|
22
22
|
* function MyComponent() {
|
|
23
23
|
* myObservable.use();
|
|
24
24
|
* return <div>{myObservable.value}</div>;
|
|
@@ -26,85 +26,85 @@ globalThis.observables = {};
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
export class Observable<T> {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
name: string
|
|
30
|
+
private _value: T
|
|
31
|
+
private subscribers: Set<(value: T) => void>
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
constructor(name: string, initialValue: T) {
|
|
34
|
+
this.name = name
|
|
35
|
+
this._value = initialValue
|
|
36
|
+
this.subscribers = new Set()
|
|
37
|
+
// @ts-expect-error
|
|
38
|
+
globalThis.observables[name] = this
|
|
39
|
+
}
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
async publish() {
|
|
42
|
+
return Promise.all([...this.subscribers].map((subscriber) => subscriber(this._value)))
|
|
43
|
+
}
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Sets a new value for the observable and notifies subscribers if the value changed.
|
|
47
|
+
*
|
|
48
|
+
* @param newValueOrSetter - The new value or a function that takes the current value and returns the new value.
|
|
49
|
+
* @returns The new value.
|
|
50
|
+
*/
|
|
51
|
+
async set(setter: ObservableSetter<T>): Promise<void>
|
|
52
|
+
async set(newValue: T): Promise<void>
|
|
53
|
+
async set(newValueOrSetter: any): Promise<void> {
|
|
54
|
+
const newValue =
|
|
55
|
+
typeof newValueOrSetter === "function"
|
|
56
|
+
? (newValueOrSetter as ObservableSetter<T>)(this._value)
|
|
57
|
+
: newValueOrSetter
|
|
58
|
+
if (!areEqualDeep(this._value, newValue)) {
|
|
59
|
+
this._value = newValue
|
|
60
|
+
await this.publish()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Register a callback to be called when the observable value changes.
|
|
66
|
+
* @param cb - The callback to be called when the value changes.
|
|
67
|
+
* @returns
|
|
68
|
+
*/
|
|
69
|
+
subscribe(cb: (value: T) => void): () => void {
|
|
70
|
+
// promisify the callback so it behaves like an async function even if it's not
|
|
71
|
+
// so that we can await all subscribers in publish()
|
|
72
|
+
const cbPromise = async (newValue: T) => cb(newValue)
|
|
73
|
+
this.subscribers.add(cbPromise)
|
|
74
|
+
return () => this.unsubscribe(cb)
|
|
75
|
+
}
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
unsubscribe(cb: (value: T) => void): void {
|
|
78
|
+
this.subscribers.delete(cb)
|
|
79
|
+
}
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
81
|
+
/**
|
|
82
|
+
* A React hook to use this observable in a component
|
|
83
|
+
*
|
|
84
|
+
* It does not return the value, but subscribes to changes and forces re-render
|
|
85
|
+
* when the value changes.
|
|
86
|
+
*
|
|
87
|
+
* @usage
|
|
88
|
+
* ```tsx
|
|
89
|
+
* const myObservable = new Observable('myObservable', 0);
|
|
90
|
+
*
|
|
91
|
+
* function MyComponent() {
|
|
92
|
+
* myObservable.use();
|
|
93
|
+
* return <div>{myObservable.value}</div>;
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
use() {
|
|
98
|
+
const [_, setValue] = useState(this.val)
|
|
99
|
+
useEffect(() => this.subscribe(setValue), [])
|
|
100
|
+
}
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
102
|
+
get val(): T {
|
|
103
|
+
// Freeze the value to avoid cases where the internal object may be mutated
|
|
104
|
+
// without triggering subscribers.
|
|
105
|
+
return Object.freeze(this._value)
|
|
106
|
+
}
|
|
107
|
+
set val(newValue: T) {
|
|
108
|
+
this.set(newValue)
|
|
109
|
+
}
|
|
110
110
|
}
|
package/esm/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export * from "@slimr/styled";
|
|
|
5
5
|
export * from "@slimr/swr";
|
|
6
6
|
export * from "react-use";
|
|
7
7
|
export * from "./merge-refs.js";
|
|
8
|
+
export * from "./Observable.js";
|
|
8
9
|
export * from "./useColorScheme.js";
|
|
9
10
|
export * from "./useMemos.js";
|
|
10
|
-
export * from "./Observable.js";
|
|
11
11
|
export * from "./useSet2.js";
|
package/esm/index.js
CHANGED
|
@@ -5,8 +5,8 @@ export * from "@slimr/styled";
|
|
|
5
5
|
export * from "@slimr/swr";
|
|
6
6
|
export * from "react-use";
|
|
7
7
|
export * from "./merge-refs.js";
|
|
8
|
+
export * from "./Observable.js";
|
|
8
9
|
export * from "./useColorScheme.js";
|
|
9
10
|
export * from "./useMemos.js";
|
|
10
|
-
export * from "./Observable.js";
|
|
11
11
|
export * from "./useSet2.js";
|
|
12
12
|
//# sourceMappingURL=index.js.map
|
package/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AAEzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AAEzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,qBAAqB,CAAA;AACnC,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA"}
|
package/esm/index.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observables.js","sourceRoot":"","sources":["../src/observables.ts"],"names":[],"mappings":""}
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slimr/react",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.74",
|
|
4
4
|
"author": "Brian Dombrowski",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"private": false,
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@slimr/forms": "^5.0.45",
|
|
35
35
|
"@slimr/markdown": "^2.1.87",
|
|
36
|
-
"@slimr/router": "^2.1.
|
|
37
|
-
"@slimr/styled": "^2.1.
|
|
38
|
-
"@slimr/swr": "^2.1.
|
|
39
|
-
"@slimr/util": "^3.2.
|
|
36
|
+
"@slimr/router": "^2.1.76",
|
|
37
|
+
"@slimr/styled": "^2.1.85",
|
|
38
|
+
"@slimr/swr": "^2.1.73",
|
|
39
|
+
"@slimr/util": "^3.2.74",
|
|
40
40
|
"react-use": "17"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
@@ -45,4 +45,4 @@
|
|
|
45
45
|
"react": "*",
|
|
46
46
|
"react-dom": "*"
|
|
47
47
|
}
|
|
48
|
-
}
|
|
48
|
+
}
|
package/src/Observable.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
// this file has exports to create an observable and useObservable react hook
|
|
2
2
|
|
|
3
|
-
import { areEqualDeep } from
|
|
4
|
-
import {
|
|
3
|
+
import { areEqualDeep } from "@slimr/util"
|
|
4
|
+
import { useEffect, useState } from "react"
|
|
5
5
|
|
|
6
|
-
type ObservableSetter<T> = (value: T) => T
|
|
6
|
+
type ObservableSetter<T> = (value: T) => T
|
|
7
7
|
|
|
8
8
|
// @ts-expect-error
|
|
9
|
-
globalThis.observables = {}
|
|
9
|
+
globalThis.observables = {}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Provides a variable with observable capabilities, like pub/sub and React hook integration.
|
|
13
|
-
*
|
|
13
|
+
*
|
|
14
14
|
* @usage
|
|
15
15
|
* ```tsx
|
|
16
16
|
* const myObservable = new Observable('myObservable', 0);
|
|
@@ -18,7 +18,7 @@ globalThis.observables = {};
|
|
|
18
18
|
* setTimeout(() => { myObservable.val = 42; }, 1000);
|
|
19
19
|
* setTimeout(() => { myObservable.set(50); }, 2000);
|
|
20
20
|
* setTimeout(() => { myObservable.set(last => last + 1); }, 1000);
|
|
21
|
-
*
|
|
21
|
+
*
|
|
22
22
|
* function MyComponent() {
|
|
23
23
|
* myObservable.use();
|
|
24
24
|
* return <div>{myObservable.value}</div>;
|
|
@@ -26,85 +26,85 @@ globalThis.observables = {};
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
export class Observable<T> {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
name: string
|
|
30
|
+
private _value: T
|
|
31
|
+
private subscribers: Set<(value: T) => void>
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
constructor(name: string, initialValue: T) {
|
|
34
|
+
this.name = name
|
|
35
|
+
this._value = initialValue
|
|
36
|
+
this.subscribers = new Set()
|
|
37
|
+
// @ts-expect-error
|
|
38
|
+
globalThis.observables[name] = this
|
|
39
|
+
}
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
async publish() {
|
|
42
|
+
return Promise.all([...this.subscribers].map((subscriber) => subscriber(this._value)))
|
|
43
|
+
}
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Sets a new value for the observable and notifies subscribers if the value changed.
|
|
47
|
+
*
|
|
48
|
+
* @param newValueOrSetter - The new value or a function that takes the current value and returns the new value.
|
|
49
|
+
* @returns The new value.
|
|
50
|
+
*/
|
|
51
|
+
async set(setter: ObservableSetter<T>): Promise<void>
|
|
52
|
+
async set(newValue: T): Promise<void>
|
|
53
|
+
async set(newValueOrSetter: any): Promise<void> {
|
|
54
|
+
const newValue =
|
|
55
|
+
typeof newValueOrSetter === "function"
|
|
56
|
+
? (newValueOrSetter as ObservableSetter<T>)(this._value)
|
|
57
|
+
: newValueOrSetter
|
|
58
|
+
if (!areEqualDeep(this._value, newValue)) {
|
|
59
|
+
this._value = newValue
|
|
60
|
+
await this.publish()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Register a callback to be called when the observable value changes.
|
|
66
|
+
* @param cb - The callback to be called when the value changes.
|
|
67
|
+
* @returns
|
|
68
|
+
*/
|
|
69
|
+
subscribe(cb: (value: T) => void): () => void {
|
|
70
|
+
// promisify the callback so it behaves like an async function even if it's not
|
|
71
|
+
// so that we can await all subscribers in publish()
|
|
72
|
+
const cbPromise = async (newValue: T) => cb(newValue)
|
|
73
|
+
this.subscribers.add(cbPromise)
|
|
74
|
+
return () => this.unsubscribe(cb)
|
|
75
|
+
}
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
unsubscribe(cb: (value: T) => void): void {
|
|
78
|
+
this.subscribers.delete(cb)
|
|
79
|
+
}
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
81
|
+
/**
|
|
82
|
+
* A React hook to use this observable in a component
|
|
83
|
+
*
|
|
84
|
+
* It does not return the value, but subscribes to changes and forces re-render
|
|
85
|
+
* when the value changes.
|
|
86
|
+
*
|
|
87
|
+
* @usage
|
|
88
|
+
* ```tsx
|
|
89
|
+
* const myObservable = new Observable('myObservable', 0);
|
|
90
|
+
*
|
|
91
|
+
* function MyComponent() {
|
|
92
|
+
* myObservable.use();
|
|
93
|
+
* return <div>{myObservable.value}</div>;
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
use() {
|
|
98
|
+
const [_, setValue] = useState(this.val)
|
|
99
|
+
useEffect(() => this.subscribe(setValue), [])
|
|
100
|
+
}
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
102
|
+
get val(): T {
|
|
103
|
+
// Freeze the value to avoid cases where the internal object may be mutated
|
|
104
|
+
// without triggering subscribers.
|
|
105
|
+
return Object.freeze(this._value)
|
|
106
|
+
}
|
|
107
|
+
set val(newValue: T) {
|
|
108
|
+
this.set(newValue)
|
|
109
|
+
}
|
|
110
110
|
}
|
package/src/index.ts
CHANGED