@oscarpalmer/mora 0.9.0 → 0.11.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/dist/batch.cjs +12 -5
- package/dist/batch.js +13 -6
- package/dist/computed.cjs +17 -25
- package/dist/computed.js +19 -27
- package/dist/effect.cjs +0 -2
- package/dist/effect.js +0 -2
- package/dist/is.cjs +4 -0
- package/dist/is.js +4 -0
- package/dist/mora.full.js +120 -74
- package/dist/reactive.cjs +39 -0
- package/dist/reactive.js +39 -0
- package/dist/signal.cjs +9 -22
- package/dist/signal.js +10 -23
- package/dist/subscription.cjs +32 -0
- package/dist/subscription.js +32 -0
- package/package.json +1 -1
- package/src/batch.ts +14 -6
- package/src/computed.ts +48 -67
- package/src/effect.ts +0 -2
- package/src/is.ts +5 -0
- package/src/reactive.ts +53 -0
- package/src/signal.ts +44 -64
- package/src/subscription.ts +47 -0
- package/types/batch.d.cts +46 -0
- package/types/batch.d.ts +3 -0
- package/types/computed.d.cts +35 -11
- package/types/computed.d.ts +7 -13
- package/types/effect.d.cts +0 -1
- package/types/effect.d.ts +0 -1
- package/types/index.d.cts +44 -24
- package/types/is.d.cts +38 -17
- package/types/is.d.ts +2 -0
- package/types/reactive.d.cts +49 -0
- package/types/reactive.d.ts +25 -0
- package/types/signal.d.cts +41 -2
- package/types/signal.d.ts +2 -7
- package/types/subscription.d.cts +52 -0
- package/types/subscription.d.ts +14 -0
package/dist/signal.js
CHANGED
|
@@ -1,20 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import { flushEffects, batchDepth } from "./batch.js";
|
|
1
|
+
import { batchedHandlers, flushEffects, batchDepth } from "./batch.js";
|
|
5
2
|
import { activeComputed } from "./computed.js";
|
|
6
|
-
import { activeEffect
|
|
7
|
-
|
|
3
|
+
import { activeEffect } from "./effect.js";
|
|
4
|
+
import { Reactive } from "./reactive.js";
|
|
5
|
+
class Signal extends Reactive {
|
|
8
6
|
constructor(value) {
|
|
9
|
-
|
|
10
|
-
Object.defineProperty(this, "$mora", {
|
|
11
|
-
value: "signal"
|
|
12
|
-
});
|
|
13
|
-
this.state = {
|
|
14
|
-
value,
|
|
15
|
-
computeds: /* @__PURE__ */ new Set(),
|
|
16
|
-
effects: /* @__PURE__ */ new Set()
|
|
17
|
-
};
|
|
7
|
+
super("signal", value);
|
|
18
8
|
}
|
|
19
9
|
/**
|
|
20
10
|
* Get the value
|
|
@@ -28,12 +18,6 @@ class Signal {
|
|
|
28
18
|
}
|
|
29
19
|
return this.state.value;
|
|
30
20
|
}
|
|
31
|
-
/**
|
|
32
|
-
* Get the value _(without reactivity)_
|
|
33
|
-
*/
|
|
34
|
-
peek() {
|
|
35
|
-
return this.state.value;
|
|
36
|
-
}
|
|
37
21
|
/**
|
|
38
22
|
* Set the value
|
|
39
23
|
*/
|
|
@@ -43,10 +27,13 @@ class Signal {
|
|
|
43
27
|
}
|
|
44
28
|
this.state.value = value;
|
|
45
29
|
for (const computed of this.state.computeds) {
|
|
46
|
-
computed.
|
|
30
|
+
computed.effect.dirty = true;
|
|
47
31
|
}
|
|
48
32
|
for (const effect of this.state.effects) {
|
|
49
|
-
|
|
33
|
+
batchedHandlers.add(effect);
|
|
34
|
+
}
|
|
35
|
+
for (const [, subscription] of this.state.subscriptions) {
|
|
36
|
+
batchedHandlers.add(subscription);
|
|
50
37
|
}
|
|
51
38
|
if (batchDepth === 0) {
|
|
52
39
|
flushEffects();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
class Subscription {
|
|
4
|
+
constructor(state, callback) {
|
|
5
|
+
this.state = state;
|
|
6
|
+
this.callback = callback;
|
|
7
|
+
callback(state.value);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function noop() {
|
|
11
|
+
}
|
|
12
|
+
function subscribe(state, callback) {
|
|
13
|
+
if (typeof callback !== "function" || state.subscriptions.has(callback)) {
|
|
14
|
+
return noop;
|
|
15
|
+
}
|
|
16
|
+
state.subscriptions.set(callback, new Subscription(state, callback));
|
|
17
|
+
return () => {
|
|
18
|
+
unsubscribe(state, callback);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function unsubscribe(state, callback) {
|
|
22
|
+
const subscription = state.subscriptions.get(callback);
|
|
23
|
+
state.subscriptions.delete(callback);
|
|
24
|
+
if (subscription != null) {
|
|
25
|
+
subscription.callback = noop;
|
|
26
|
+
subscription.state = void 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.Subscription = Subscription;
|
|
30
|
+
exports.noop = noop;
|
|
31
|
+
exports.subscribe = subscribe;
|
|
32
|
+
exports.unsubscribe = unsubscribe;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class Subscription {
|
|
2
|
+
constructor(state, callback) {
|
|
3
|
+
this.state = state;
|
|
4
|
+
this.callback = callback;
|
|
5
|
+
callback(state.value);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
function noop() {
|
|
9
|
+
}
|
|
10
|
+
function subscribe(state, callback) {
|
|
11
|
+
if (typeof callback !== "function" || state.subscriptions.has(callback)) {
|
|
12
|
+
return noop;
|
|
13
|
+
}
|
|
14
|
+
state.subscriptions.set(callback, new Subscription(state, callback));
|
|
15
|
+
return () => {
|
|
16
|
+
unsubscribe(state, callback);
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function unsubscribe(state, callback) {
|
|
20
|
+
const subscription = state.subscriptions.get(callback);
|
|
21
|
+
state.subscriptions.delete(callback);
|
|
22
|
+
if (subscription != null) {
|
|
23
|
+
subscription.callback = noop;
|
|
24
|
+
subscription.state = void 0;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
Subscription,
|
|
29
|
+
noop,
|
|
30
|
+
subscribe,
|
|
31
|
+
unsubscribe
|
|
32
|
+
};
|
package/package.json
CHANGED
package/src/batch.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {type Effect, runEffect} from './effect';
|
|
2
|
+
import {isEffect} from './is';
|
|
3
|
+
import type {Subscription} from './subscription';
|
|
2
4
|
|
|
3
5
|
export function flushEffects(): void {
|
|
4
|
-
while (batchDepth === 0 &&
|
|
5
|
-
const
|
|
6
|
+
while (batchDepth === 0 && batchedHandlers.size > 0) {
|
|
7
|
+
const handlers = [...batchedHandlers];
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
batchedHandlers.clear();
|
|
8
10
|
|
|
9
|
-
for (const
|
|
10
|
-
|
|
11
|
+
for (const handler of handlers) {
|
|
12
|
+
if (isEffect(handler)) {
|
|
13
|
+
runEffect(handler);
|
|
14
|
+
} else {
|
|
15
|
+
handler.callback(handler.state.value);
|
|
16
|
+
}
|
|
11
17
|
}
|
|
12
18
|
}
|
|
13
19
|
}
|
|
@@ -30,4 +36,6 @@ export function stopBatch(): void {
|
|
|
30
36
|
flushEffects();
|
|
31
37
|
}
|
|
32
38
|
|
|
39
|
+
export const batchedHandlers = new Set<Effect | Subscription<unknown>>();
|
|
40
|
+
|
|
33
41
|
export let batchDepth = 0;
|
package/src/computed.ts
CHANGED
|
@@ -1,97 +1,78 @@
|
|
|
1
|
-
import {batchDepth} from './batch';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
effect,
|
|
7
|
-
runEffect,
|
|
8
|
-
} from './effect';
|
|
9
|
-
|
|
10
|
-
type ComputedState<Value> = {
|
|
11
|
-
computeds: Set<Computed<unknown>>;
|
|
1
|
+
import {batchDepth, batchedHandlers} from './batch';
|
|
2
|
+
import {type Effect, activeEffect, effect, runEffect} from './effect';
|
|
3
|
+
import {Reactive, type ReactiveState} from './reactive';
|
|
4
|
+
|
|
5
|
+
type ComputedEffect = {
|
|
12
6
|
dirty: boolean;
|
|
13
|
-
|
|
14
|
-
effects: Set<Effect>;
|
|
15
|
-
value: Value;
|
|
7
|
+
instance: Effect;
|
|
16
8
|
};
|
|
17
9
|
|
|
18
10
|
export type InternalComputed = {
|
|
19
|
-
readonly
|
|
11
|
+
readonly effect: ComputedEffect;
|
|
12
|
+
readonly state: ReactiveState<unknown>;
|
|
20
13
|
};
|
|
21
14
|
|
|
22
15
|
export let activeComputed: Computed<unknown> | undefined;
|
|
23
16
|
|
|
24
|
-
export class Computed<Value> {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
export class Computed<Value> extends Reactive<Value> {
|
|
18
|
+
private readonly effect: ComputedEffect = {
|
|
19
|
+
dirty: true,
|
|
20
|
+
instance: undefined as never,
|
|
21
|
+
};
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
value: 'computed',
|
|
32
|
-
});
|
|
23
|
+
constructor(callback: () => Value) {
|
|
24
|
+
super('computed', undefined as never);
|
|
33
25
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
effect: undefined as never,
|
|
38
|
-
effects: new Set(),
|
|
39
|
-
value: undefined as never,
|
|
40
|
-
};
|
|
26
|
+
this.effect.instance = effect(() => {
|
|
27
|
+
if (this.effect.dirty) {
|
|
28
|
+
const previousComputed = activeComputed;
|
|
41
29
|
|
|
42
|
-
|
|
43
|
-
if (this.state.dirty) {
|
|
44
|
-
const previousComputed = activeComputed;
|
|
30
|
+
activeComputed = this as never;
|
|
45
31
|
|
|
46
|
-
|
|
32
|
+
const value = callback();
|
|
47
33
|
|
|
48
|
-
|
|
34
|
+
activeComputed = previousComputed;
|
|
49
35
|
|
|
50
|
-
|
|
36
|
+
if (!Object.is(this.state.value, value)) {
|
|
37
|
+
this.state.value = value;
|
|
51
38
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
for (const computed of this.state.computeds) {
|
|
56
|
-
computed.state.dirty = true;
|
|
57
|
-
}
|
|
39
|
+
for (const computed of this.state.computeds) {
|
|
40
|
+
computed.effect.dirty = true;
|
|
41
|
+
}
|
|
58
42
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
43
|
+
for (const effect of this.state.effects) {
|
|
44
|
+
batchedHandlers.add(effect);
|
|
62
45
|
}
|
|
63
46
|
|
|
64
|
-
this.state.
|
|
47
|
+
for (const [, subscription] of this.state.subscriptions) {
|
|
48
|
+
subscription.callback(value);
|
|
49
|
+
}
|
|
65
50
|
}
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
51
|
|
|
69
|
-
|
|
70
|
-
* Get the value
|
|
71
|
-
*/
|
|
72
|
-
get(): Value {
|
|
73
|
-
if (activeComputed != null && activeComputed !== this) {
|
|
74
|
-
this.state.computeds.add(activeComputed);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (activeEffect != null && activeEffect !== this.state.effect) {
|
|
78
|
-
this.state.effects.add(activeEffect);
|
|
52
|
+
this.effect.dirty = false;
|
|
79
53
|
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
80
56
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Get the value
|
|
59
|
+
*/
|
|
60
|
+
get(): Value {
|
|
61
|
+
if (activeComputed != null && activeComputed !== this) {
|
|
62
|
+
this.state.computeds.add(activeComputed);
|
|
63
|
+
}
|
|
84
64
|
|
|
85
|
-
|
|
65
|
+
if (activeEffect != null && activeEffect !== this.effect.instance) {
|
|
66
|
+
this.state.effects.add(activeEffect);
|
|
86
67
|
}
|
|
87
68
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
*/
|
|
91
|
-
peek(): Value {
|
|
92
|
-
return this.state.value;
|
|
69
|
+
if (this.effect.dirty && batchDepth === 0) {
|
|
70
|
+
runEffect(this.effect.instance);
|
|
93
71
|
}
|
|
72
|
+
|
|
73
|
+
return this.state.value;
|
|
94
74
|
}
|
|
75
|
+
}
|
|
95
76
|
|
|
96
77
|
/**
|
|
97
78
|
* Create a computed value
|
package/src/effect.ts
CHANGED
package/src/is.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
2
|
import type {Computed} from './computed';
|
|
3
3
|
import type {Effect} from './effect';
|
|
4
|
+
import type {Reactive} from './reactive';
|
|
4
5
|
import type {Signal} from './signal';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -26,6 +27,10 @@ function isMora<T>(value: unknown, name: string): value is T {
|
|
|
26
27
|
);
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
export function isReactive(value: unknown): value is Reactive<unknown> {
|
|
31
|
+
return isComputed(value) || isSignal(value);
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
/**
|
|
30
35
|
* Is the value a signal?
|
|
31
36
|
*/
|
package/src/reactive.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type {Computed} from './computed';
|
|
2
|
+
import type {Effect} from './effect';
|
|
3
|
+
import {
|
|
4
|
+
type Subscription,
|
|
5
|
+
type Unsubscribe,
|
|
6
|
+
subscribe,
|
|
7
|
+
unsubscribe,
|
|
8
|
+
} from './subscription';
|
|
9
|
+
|
|
10
|
+
export abstract class Reactive<Value> {
|
|
11
|
+
protected readonly state: ReactiveState<Value> = {
|
|
12
|
+
computeds: new Set(),
|
|
13
|
+
effects: new Set(),
|
|
14
|
+
subscriptions: new Map(),
|
|
15
|
+
value: undefined as never,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
constructor(name: string, value: Value) {
|
|
19
|
+
this.state.value = value;
|
|
20
|
+
|
|
21
|
+
Object.defineProperty(this, '$mora', {
|
|
22
|
+
value: name,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get the value _(without reactivity)_
|
|
28
|
+
*/
|
|
29
|
+
peek(): Value {
|
|
30
|
+
return this.state.value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Subscribe to changes
|
|
35
|
+
*/
|
|
36
|
+
subscribe(callback: (value: Value) => void): Unsubscribe {
|
|
37
|
+
return subscribe(this.state, callback);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Unsubscribe from changes
|
|
42
|
+
*/
|
|
43
|
+
unsubscribe(callback: (value: Value) => void): void {
|
|
44
|
+
unsubscribe(this.state, callback);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type ReactiveState<Value> = {
|
|
49
|
+
computeds: Set<Computed<unknown>>;
|
|
50
|
+
effects: Set<Effect>;
|
|
51
|
+
subscriptions: Map<(value: Value) => void, Subscription<Value>>;
|
|
52
|
+
value: Value;
|
|
53
|
+
};
|
package/src/signal.ts
CHANGED
|
@@ -1,83 +1,63 @@
|
|
|
1
|
-
import {batchDepth, flushEffects} from './batch';
|
|
2
|
-
import {type
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
1
|
+
import {batchDepth, batchedHandlers, flushEffects} from './batch';
|
|
2
|
+
import {type InternalComputed, activeComputed} from './computed';
|
|
3
|
+
import {activeEffect} from './effect';
|
|
4
|
+
import {Reactive} from './reactive';
|
|
5
|
+
|
|
6
|
+
export class Signal<Value> extends Reactive<Value> {
|
|
7
|
+
constructor(value: Value) {
|
|
8
|
+
super('signal', value);
|
|
9
|
+
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Get the value
|
|
13
|
+
*/
|
|
14
|
+
get(): Value {
|
|
15
|
+
if (activeComputed != null) {
|
|
16
|
+
this.state.computeds.add(activeComputed);
|
|
17
|
+
}
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
if (activeEffect != null) {
|
|
20
|
+
this.state.effects.add(activeEffect);
|
|
21
|
+
}
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
value: 'signal',
|
|
19
|
-
});
|
|
23
|
+
return this.state.value;
|
|
24
|
+
}
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Set the value
|
|
28
|
+
*/
|
|
29
|
+
set(value: Value): void {
|
|
30
|
+
if (Object.is(this.state.value, value)) {
|
|
31
|
+
return;
|
|
26
32
|
}
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
* Get the value
|
|
30
|
-
*/
|
|
31
|
-
get(): Value {
|
|
32
|
-
if (activeComputed != null) {
|
|
33
|
-
this.state.computeds.add(activeComputed);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (activeEffect != null) {
|
|
37
|
-
this.state.effects.add(activeEffect);
|
|
38
|
-
}
|
|
34
|
+
this.state.value = value;
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
for (const computed of this.state.computeds) {
|
|
37
|
+
(computed as unknown as InternalComputed).effect.dirty = true;
|
|
41
38
|
}
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
*/
|
|
46
|
-
peek(): Value {
|
|
47
|
-
return this.state.value;
|
|
40
|
+
for (const effect of this.state.effects) {
|
|
41
|
+
batchedHandlers.add(effect);
|
|
48
42
|
}
|
|
49
43
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
*/
|
|
53
|
-
set(value: Value): void {
|
|
54
|
-
if (Object.is(this.state.value, value)) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
this.state.value = value;
|
|
59
|
-
|
|
60
|
-
for (const computed of this.state.computeds) {
|
|
61
|
-
(computed as unknown as InternalComputed).state.dirty = true;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
for (const effect of this.state.effects) {
|
|
65
|
-
dirtyEffects.add(effect);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (batchDepth === 0) {
|
|
69
|
-
flushEffects();
|
|
70
|
-
}
|
|
44
|
+
for (const [, subscription] of this.state.subscriptions) {
|
|
45
|
+
batchedHandlers.add(subscription as never);
|
|
71
46
|
}
|
|
72
47
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
*/
|
|
76
|
-
update(callback: (value: Value) => Value): void {
|
|
77
|
-
this.set(callback(this.state.value));
|
|
48
|
+
if (batchDepth === 0) {
|
|
49
|
+
flushEffects();
|
|
78
50
|
}
|
|
79
51
|
}
|
|
80
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Update the value
|
|
55
|
+
*/
|
|
56
|
+
update(callback: (value: Value) => Value): void {
|
|
57
|
+
this.set(callback(this.state.value));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
81
61
|
export function signal<Value>(value: Value): Signal<Value> {
|
|
82
62
|
return new Signal(value);
|
|
83
63
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import type {ReactiveState} from './reactive';
|
|
3
|
+
|
|
4
|
+
export class Subscription<Value> {
|
|
5
|
+
constructor(
|
|
6
|
+
public state: ReactiveState<Value>,
|
|
7
|
+
public callback: GenericCallback,
|
|
8
|
+
) {
|
|
9
|
+
callback(state.value);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Unsubscribe from changes
|
|
15
|
+
*/
|
|
16
|
+
export type Unsubscribe = () => void;
|
|
17
|
+
|
|
18
|
+
export function noop(): void {}
|
|
19
|
+
|
|
20
|
+
export function subscribe<Value>(
|
|
21
|
+
state: ReactiveState<Value>,
|
|
22
|
+
callback: (value: Value) => void,
|
|
23
|
+
): Unsubscribe {
|
|
24
|
+
if (typeof callback !== 'function' || state.subscriptions.has(callback)) {
|
|
25
|
+
return noop;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
state.subscriptions.set(callback, new Subscription(state, callback));
|
|
29
|
+
|
|
30
|
+
return () => {
|
|
31
|
+
unsubscribe(state, callback);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function unsubscribe<Value>(
|
|
36
|
+
state: ReactiveState<Value>,
|
|
37
|
+
callback: (value: Value) => void,
|
|
38
|
+
): void {
|
|
39
|
+
const subscription = state.subscriptions.get(callback);
|
|
40
|
+
|
|
41
|
+
state.subscriptions.delete(callback);
|
|
42
|
+
|
|
43
|
+
if (subscription != null) {
|
|
44
|
+
subscription.callback = noop;
|
|
45
|
+
subscription.state = undefined as never;
|
|
46
|
+
}
|
|
47
|
+
}
|
package/types/batch.d.cts
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
// Generated by dts-bundle-generator v9.5.1
|
|
2
2
|
|
|
3
|
+
export type GenericCallback = (...args: any[]) => any;
|
|
4
|
+
declare class Effect {
|
|
5
|
+
private readonly $mora;
|
|
6
|
+
private readonly state;
|
|
7
|
+
constructor(callback: GenericCallback);
|
|
8
|
+
}
|
|
9
|
+
declare class Computed<Value> extends Reactive<Value> {
|
|
10
|
+
private readonly effect;
|
|
11
|
+
constructor(callback: () => Value);
|
|
12
|
+
/**
|
|
13
|
+
* Get the value
|
|
14
|
+
*/
|
|
15
|
+
get(): Value;
|
|
16
|
+
}
|
|
17
|
+
declare abstract class Reactive<Value> {
|
|
18
|
+
protected readonly state: ReactiveState<Value>;
|
|
19
|
+
constructor(name: string, value: Value);
|
|
20
|
+
/**
|
|
21
|
+
* Get the value _(without reactivity)_
|
|
22
|
+
*/
|
|
23
|
+
peek(): Value;
|
|
24
|
+
/**
|
|
25
|
+
* Subscribe to changes
|
|
26
|
+
*/
|
|
27
|
+
subscribe(callback: (value: Value) => void): Unsubscribe;
|
|
28
|
+
/**
|
|
29
|
+
* Unsubscribe from changes
|
|
30
|
+
*/
|
|
31
|
+
unsubscribe(callback: (value: Value) => void): void;
|
|
32
|
+
}
|
|
33
|
+
export type ReactiveState<Value> = {
|
|
34
|
+
computeds: Set<Computed<unknown>>;
|
|
35
|
+
effects: Set<Effect>;
|
|
36
|
+
subscriptions: Map<(value: Value) => void, Subscription<Value>>;
|
|
37
|
+
value: Value;
|
|
38
|
+
};
|
|
39
|
+
declare class Subscription<Value> {
|
|
40
|
+
state: ReactiveState<Value>;
|
|
41
|
+
callback: GenericCallback;
|
|
42
|
+
constructor(state: ReactiveState<Value>, callback: GenericCallback);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Unsubscribe from changes
|
|
46
|
+
*/
|
|
47
|
+
export type Unsubscribe = () => void;
|
|
3
48
|
export declare function flushEffects(): void;
|
|
4
49
|
/**
|
|
5
50
|
* Start batching effects _(use `stopBatch` to flush and run batched effects)_
|
|
@@ -9,6 +54,7 @@ export declare function startBatch(): void;
|
|
|
9
54
|
* Stop batching effects and flush _(run)_ them
|
|
10
55
|
*/
|
|
11
56
|
export declare function stopBatch(): void;
|
|
57
|
+
export declare const batchedHandlers: Set<Effect | Subscription<unknown>>;
|
|
12
58
|
export declare let batchDepth: number;
|
|
13
59
|
|
|
14
60
|
export {};
|
package/types/batch.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type Effect } from './effect';
|
|
2
|
+
import type { Subscription } from './subscription';
|
|
1
3
|
export declare function flushEffects(): void;
|
|
2
4
|
/**
|
|
3
5
|
* Start batching effects _(use `stopBatch` to flush and run batched effects)_
|
|
@@ -7,4 +9,5 @@ export declare function startBatch(): void;
|
|
|
7
9
|
* Stop batching effects and flush _(run)_ them
|
|
8
10
|
*/
|
|
9
11
|
export declare function stopBatch(): void;
|
|
12
|
+
export declare const batchedHandlers: Set<Effect | Subscription<unknown>>;
|
|
10
13
|
export declare let batchDepth: number;
|