@oscarpalmer/mora 0.32.0 → 0.33.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.mjs +2 -2
- package/dist/constants.d.mts +2 -0
- package/dist/constants.mjs +3 -1
- package/dist/effect.d.mts +1 -0
- package/dist/effect.mjs +8 -5
- package/dist/helpers/is.d.mts +6 -6
- package/dist/helpers/misc.d.mts +4 -0
- package/dist/helpers/misc.mjs +9 -0
- package/dist/helpers/proxy.d.mts +8 -10
- package/dist/helpers/proxy.mjs +71 -33
- package/dist/helpers/subscription.d.mts +4 -4
- package/dist/helpers/subscription.mjs +16 -13
- package/dist/helpers/value.d.mts +8 -7
- package/dist/helpers/value.mjs +35 -22
- package/dist/models.d.mts +47 -24
- package/dist/models.mjs +1 -0
- package/dist/mora.full.mjs +307 -236
- package/dist/value/array.d.mts +1 -0
- package/dist/value/array.mjs +69 -61
- package/dist/value/computed.d.mts +3 -1
- package/dist/value/computed.mjs +39 -25
- package/dist/value/readonly.d.mts +3 -3
- package/dist/value/readonly.mjs +31 -24
- package/dist/value/signal.d.mts +1 -0
- package/dist/value/signal.mjs +27 -20
- package/dist/value/store.d.mts +1 -0
- package/dist/value/store.mjs +23 -41
- package/package.json +1 -1
- package/src/batch.ts +2 -2
- package/src/constants.ts +4 -0
- package/src/effect.ts +16 -11
- package/src/helpers/is.ts +6 -6
- package/src/helpers/misc.ts +15 -0
- package/src/helpers/proxy.ts +116 -89
- package/src/helpers/subscription.ts +46 -35
- package/src/helpers/value.ts +61 -35
- package/src/models.ts +54 -28
- package/src/value/array.ts +103 -124
- package/src/value/computed.ts +70 -40
- package/src/value/readonly.ts +54 -41
- package/src/value/signal.ts +46 -35
- package/src/value/store.ts +36 -83
- package/dist/value/reactive.d.mts +0 -4
- package/dist/value/reactive.mjs +0 -15
- package/src/value/reactive.ts +0 -27
package/src/value/readonly.ts
CHANGED
|
@@ -2,58 +2,71 @@ import {
|
|
|
2
2
|
NAME_MORA,
|
|
3
3
|
NAME_READONLY,
|
|
4
4
|
SUBSCRIPTION_TYPE_FROZEN,
|
|
5
|
-
|
|
5
|
+
SUBSCRIPTION_TYPE_ORIGINAL,
|
|
6
|
+
SYMBOL_STATE,
|
|
6
7
|
} from '../constants';
|
|
7
|
-
import {
|
|
8
|
-
import {getFrozenValue,
|
|
9
|
-
import type {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
import {subscribeToReadonly} from '../helpers/subscription';
|
|
9
|
+
import {getFrozenValue, getSignalValue, getStringValue, peekSignalValue} from '../helpers/value';
|
|
10
|
+
import type {ReadonlyFrozenSignal, ReadonlySignal, SignalState, InternalSignal} from '../models';
|
|
11
|
+
|
|
12
|
+
// #region Instance
|
|
13
|
+
|
|
14
|
+
function Readonly(this: any, state: SignalState, frozen: boolean) {
|
|
15
|
+
this[SYMBOL_STATE] = state;
|
|
16
|
+
|
|
17
|
+
Object.defineProperty(this, SUBSCRIPTION_TYPE_FROZEN, {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
value: frozen,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
Readonly.prototype[NAME_MORA] = NAME_READONLY;
|
|
24
|
+
|
|
25
|
+
Readonly.prototype.subscribe = subscribeToReadonly;
|
|
26
|
+
Readonly.prototype.toString = getStringValue;
|
|
27
|
+
|
|
28
|
+
Readonly.prototype.get = function () {
|
|
29
|
+
return getReadonlyValue(this, false, this[SUBSCRIPTION_TYPE_FROZEN]);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
Readonly.prototype.peek = function (copy?: boolean) {
|
|
33
|
+
return getReadonlyValue(this, true, this[SUBSCRIPTION_TYPE_FROZEN], copy);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
Readonly.prototype.toJSON = function () {
|
|
37
|
+
return this[SYMBOL_STATE].value;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// #endregion
|
|
15
41
|
|
|
16
42
|
// #region Functions
|
|
17
43
|
|
|
18
44
|
export function getReadonlyInstance<Value>(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
frozen: boolean,
|
|
45
|
+
this: InternalSignal,
|
|
46
|
+
frozen?: never,
|
|
22
47
|
): ReadonlySignal<Value> {
|
|
23
|
-
const key = frozen ?
|
|
48
|
+
const key = (frozen === true ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_ORIGINAL) as never;
|
|
49
|
+
|
|
50
|
+
this[SYMBOL_STATE].readonlies ??= {};
|
|
24
51
|
|
|
25
|
-
|
|
52
|
+
this[SYMBOL_STATE].readonlies[key] ??= getReadonlySignal(
|
|
53
|
+
this[SYMBOL_STATE],
|
|
54
|
+
frozen === true,
|
|
55
|
+
) as never;
|
|
26
56
|
|
|
27
|
-
return
|
|
57
|
+
return this[SYMBOL_STATE].readonlies[key] as never;
|
|
28
58
|
}
|
|
29
59
|
|
|
30
|
-
export function getReadonlySignal
|
|
31
|
-
state:
|
|
60
|
+
export function getReadonlySignal(
|
|
61
|
+
state: SignalState,
|
|
32
62
|
frozen: boolean,
|
|
33
|
-
): ReadonlySignal<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const instance = {
|
|
37
|
-
get: () => getReadonlyValue(state, false, frozen),
|
|
38
|
-
peek: (copy?: boolean) => getReadonlyValue(state, true, frozen, copy),
|
|
39
|
-
subscribe: (callback: never) => subscribeToReactive(type, state, callback),
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
Object.defineProperties(instance, {
|
|
43
|
-
[NAME_MORA]: {
|
|
44
|
-
value: NAME_READONLY,
|
|
45
|
-
},
|
|
46
|
-
frozen: {
|
|
47
|
-
enumerable: true,
|
|
48
|
-
value: frozen,
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
return Object.freeze(instance) as never;
|
|
63
|
+
): ReadonlySignal<unknown> | ReadonlyFrozenSignal<unknown> {
|
|
64
|
+
// @ts-expect-error All good, no worries :-)
|
|
65
|
+
return new Readonly(state, frozen);
|
|
53
66
|
}
|
|
54
67
|
|
|
55
|
-
function getReadonlyValue
|
|
56
|
-
|
|
68
|
+
function getReadonlyValue(
|
|
69
|
+
instance: InternalSignal,
|
|
57
70
|
peek: boolean,
|
|
58
71
|
frozen: boolean,
|
|
59
72
|
copy?: boolean,
|
|
@@ -61,9 +74,9 @@ function getReadonlyValue<Value>(
|
|
|
61
74
|
let value: unknown;
|
|
62
75
|
|
|
63
76
|
if (peek) {
|
|
64
|
-
value =
|
|
77
|
+
value = peekSignalValue.call(instance, copy === true);
|
|
65
78
|
} else {
|
|
66
|
-
value =
|
|
79
|
+
value = getSignalValue.call(instance);
|
|
67
80
|
}
|
|
68
81
|
|
|
69
82
|
return frozen ? getFrozenValue(value) : value;
|
package/src/value/signal.ts
CHANGED
|
@@ -1,23 +1,56 @@
|
|
|
1
|
-
import {NAME_MORA, NAME_SIGNAL} from '../constants';
|
|
1
|
+
import {NAME_MORA, NAME_SIGNAL, SYMBOL_STATE} from '../constants';
|
|
2
|
+
import {getState} from '../helpers/misc';
|
|
2
3
|
import {subscribeToSignal} from '../helpers/subscription';
|
|
3
4
|
import {
|
|
4
5
|
emitValue,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
getSignalValue,
|
|
7
|
+
getStringValue,
|
|
8
|
+
handleSignalValue,
|
|
9
|
+
peekSignalValue,
|
|
10
|
+
updateSignalValue,
|
|
9
11
|
} from '../helpers/value';
|
|
10
|
-
import type {ReactiveOptions,
|
|
11
|
-
import {reactive} from './reactive';
|
|
12
|
+
import type {ReactiveOptions, Signal, InternalSignal} from '../models';
|
|
12
13
|
import {getReadonlyInstance} from './readonly';
|
|
13
14
|
|
|
15
|
+
// #region Instance
|
|
16
|
+
|
|
17
|
+
function Signal(this: any, value: unknown, options?: ReactiveOptions<unknown>) {
|
|
18
|
+
this[SYMBOL_STATE] = getState(undefined, options);
|
|
19
|
+
|
|
20
|
+
handleSignalValue(this, value, setAndEmit);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
Signal.prototype[NAME_MORA] = NAME_SIGNAL;
|
|
24
|
+
|
|
25
|
+
Signal.prototype.asReadonly = getReadonlyInstance;
|
|
26
|
+
Signal.prototype.get = getSignalValue;
|
|
27
|
+
Signal.prototype.peek = peekSignalValue;
|
|
28
|
+
Signal.prototype.subscribe = subscribeToSignal;
|
|
29
|
+
Signal.prototype.toString = getStringValue;
|
|
30
|
+
|
|
31
|
+
Signal.prototype.set = function (value: never) {
|
|
32
|
+
return handleSignalValue(this, value, setAndEmit);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
Signal.prototype.toJSON = function () {
|
|
36
|
+
return this[SYMBOL_STATE].value;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
Signal.prototype.update = function (callback: never) {
|
|
40
|
+
return updateSignalValue(this, callback, setAndEmit);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// #endregion
|
|
44
|
+
|
|
14
45
|
// #region Functions
|
|
15
46
|
|
|
16
|
-
function setAndEmit
|
|
17
|
-
|
|
47
|
+
function setAndEmit(instance: InternalSignal, value: unknown): void {
|
|
48
|
+
const state = instance[SYMBOL_STATE];
|
|
49
|
+
|
|
50
|
+
if (!(state.equal ?? Object.is)(state.value as never, value as never)) {
|
|
18
51
|
state.value = value;
|
|
19
52
|
|
|
20
|
-
emitValue(
|
|
53
|
+
emitValue(instance);
|
|
21
54
|
}
|
|
22
55
|
}
|
|
23
56
|
|
|
@@ -54,31 +87,9 @@ export function signal<Value>(
|
|
|
54
87
|
*/
|
|
55
88
|
export function signal<Value>(value: Value, options?: ReactiveOptions<Value>): Signal<Value>;
|
|
56
89
|
|
|
57
|
-
export function signal<
|
|
58
|
-
|
|
59
|
-
options
|
|
60
|
-
): Signal<Value> {
|
|
61
|
-
const [rx, state] = reactive<Value>(undefined as unknown as Value, options);
|
|
62
|
-
|
|
63
|
-
const readonlies: ReadonlyInstances<Value> = {};
|
|
64
|
-
|
|
65
|
-
const instance = {
|
|
66
|
-
...rx,
|
|
67
|
-
asReadonly: (frozen?: never) => getReadonlyInstance(state, readonlies, frozen === true),
|
|
68
|
-
get: () => getSimpleValue(state),
|
|
69
|
-
peek: (copy?: boolean) => peekSimpleValue(state.value, copy === true),
|
|
70
|
-
set: (value: never) => handleSimpleValue(state, value, setAndEmit),
|
|
71
|
-
subscribe: (callback: never, copy?: never) => subscribeToSignal(state, callback, copy === true),
|
|
72
|
-
update: (callback: never) => updateSimpleValue(state, callback, setAndEmit),
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
Object.defineProperty(instance, NAME_MORA, {
|
|
76
|
-
value: NAME_SIGNAL,
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
handleSimpleValue(state, value, setAndEmit);
|
|
80
|
-
|
|
81
|
-
return Object.freeze(instance) as never;
|
|
90
|
+
export function signal(value: unknown, options?: ReactiveOptions<unknown>): Signal<unknown> {
|
|
91
|
+
// @ts-expect-error All good, no worries :-)
|
|
92
|
+
return new Signal(value, options);
|
|
82
93
|
}
|
|
83
94
|
|
|
84
95
|
// #endregion
|
package/src/value/store.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import type {PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import {NAME_MORA, NAME_STORE, SYMBOL_STATE} from '../constants';
|
|
3
|
+
import {getState} from '../helpers/misc';
|
|
4
4
|
import {
|
|
5
5
|
emitProxyValues,
|
|
6
6
|
getValueInProxy,
|
|
@@ -10,61 +10,46 @@ import {
|
|
|
10
10
|
updateProxyValue,
|
|
11
11
|
} from '../helpers/proxy';
|
|
12
12
|
import {subscribeToProxy} from '../helpers/subscription';
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
-
ComputedEffect,
|
|
16
|
-
ReactiveOptions,
|
|
17
|
-
ReactiveState,
|
|
18
|
-
ReactiveStore,
|
|
19
|
-
ReadonlyInstances,
|
|
20
|
-
} from '../models';
|
|
21
|
-
import {reactive} from './reactive';
|
|
13
|
+
import {getStringValue} from '../helpers/value';
|
|
14
|
+
import type {ReactiveOptions, ReactiveStore} from '../models';
|
|
22
15
|
import {getReadonlyInstance} from './readonly';
|
|
23
16
|
|
|
24
|
-
// #region
|
|
25
|
-
|
|
26
|
-
function setPropertyValue<Value extends PlainObject, Item = Value>(
|
|
27
|
-
state: ReactiveState<Value, Item>,
|
|
28
|
-
key: unknown,
|
|
29
|
-
value: unknown,
|
|
30
|
-
): void {
|
|
31
|
-
(state.value as PlainObject)[key as Key] = value;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function setStoreValue<Value extends PlainObject, Item = Value>(
|
|
35
|
-
state: ReactiveState<Value, Item>,
|
|
36
|
-
value: PlainObject | undefined,
|
|
37
|
-
): void {
|
|
38
|
-
startBatch();
|
|
39
|
-
|
|
40
|
-
const actual = value ?? {};
|
|
41
|
-
const proxy = state.value as PlainObject;
|
|
17
|
+
// #region Instance
|
|
42
18
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
19
|
+
function ReactiveStore(this: any, value: never, options?: ReactiveOptions<unknown>) {
|
|
20
|
+
this[SYMBOL_STATE] = {
|
|
21
|
+
...getState(undefined, options),
|
|
22
|
+
isArray: false,
|
|
23
|
+
};
|
|
47
24
|
|
|
48
|
-
|
|
49
|
-
|
|
25
|
+
this[SYMBOL_STATE].value = new Proxy(
|
|
26
|
+
{},
|
|
27
|
+
{
|
|
28
|
+
set: (target, property, value) => setValueInProxy(this, target, property, value),
|
|
29
|
+
},
|
|
30
|
+
);
|
|
50
31
|
|
|
51
|
-
|
|
52
|
-
|
|
32
|
+
setProxyValue.call(this, value);
|
|
33
|
+
}
|
|
53
34
|
|
|
54
|
-
|
|
35
|
+
ReactiveStore.prototype[NAME_MORA] = NAME_STORE;
|
|
55
36
|
|
|
56
|
-
|
|
57
|
-
|
|
37
|
+
ReactiveStore.prototype.asReadonly = getReadonlyInstance;
|
|
38
|
+
ReactiveStore.prototype.get = getValueInProxy;
|
|
39
|
+
ReactiveStore.prototype.notify = emitProxyValues;
|
|
40
|
+
ReactiveStore.prototype.peek = peekValueInProxy;
|
|
41
|
+
ReactiveStore.prototype.set = setProxyValue;
|
|
42
|
+
ReactiveStore.prototype.subscribe = subscribeToProxy;
|
|
43
|
+
ReactiveStore.prototype.toString = getStringValue;
|
|
44
|
+
ReactiveStore.prototype.update = updateProxyValue;
|
|
58
45
|
|
|
59
|
-
|
|
60
|
-
|
|
46
|
+
ReactiveStore.prototype.toJSON = function () {
|
|
47
|
+
return this[SYMBOL_STATE].value;
|
|
48
|
+
};
|
|
61
49
|
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
}
|
|
50
|
+
// #endregion
|
|
65
51
|
|
|
66
|
-
|
|
67
|
-
}
|
|
52
|
+
// #region Functions
|
|
68
53
|
|
|
69
54
|
/**
|
|
70
55
|
* Create a reactive store from a function result
|
|
@@ -102,41 +87,9 @@ export function store<Value extends PlainObject>(
|
|
|
102
87
|
options?: ReactiveOptions<Value>,
|
|
103
88
|
): ReactiveStore<Value>;
|
|
104
89
|
|
|
105
|
-
export function store<
|
|
106
|
-
|
|
107
|
-
options
|
|
108
|
-
): ReactiveStore<Value> {
|
|
109
|
-
const [rx, state] = reactive<Value>(undefined as never, options);
|
|
110
|
-
|
|
111
|
-
const isArray = false;
|
|
112
|
-
const keyed = new Map<Key, [Computed<unknown>, ComputedEffect]>();
|
|
113
|
-
const readonlies: ReadonlyInstances<Value> = {};
|
|
114
|
-
|
|
115
|
-
state.value = new Proxy({} as Value, {
|
|
116
|
-
set: (target, property, value) => setValueInProxy(isArray, state, target, property, value),
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const instance = {
|
|
120
|
-
...rx,
|
|
121
|
-
asReadonly: (frozen?: never) => getReadonlyInstance(state, readonlies, frozen === true),
|
|
122
|
-
get: (value?: never) => getValueInProxy(isArray, instance as never, state, keyed, value),
|
|
123
|
-
notify: () => emitProxyValues(state, keyed),
|
|
124
|
-
peek: (first?: never, second?: never) => peekValueInProxy(isArray, state, first, second),
|
|
125
|
-
set: (first?: never, second?: never) =>
|
|
126
|
-
setProxyValue<Value>(isArray, state, setStoreValue, setPropertyValue, first, second),
|
|
127
|
-
subscribe: (first: never, second?: never, third?: never) =>
|
|
128
|
-
subscribeToProxy(isArray, instance as never, state, keyed, first, second, third),
|
|
129
|
-
update: (callback: never) =>
|
|
130
|
-
updateProxyValue(isArray, state, setStoreValue, setPropertyValue, callback),
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
Object.defineProperty(instance, NAME_MORA, {
|
|
134
|
-
value: NAME_STORE,
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
instance.set(value as never);
|
|
138
|
-
|
|
139
|
-
return Object.freeze(instance) as never;
|
|
90
|
+
export function store(value: unknown, options?: ReactiveOptions<unknown>): ReactiveStore<unknown> {
|
|
91
|
+
// @ts-expect-error All good, no worries :-)
|
|
92
|
+
return new ReactiveStore(value, options);
|
|
140
93
|
}
|
|
141
94
|
|
|
142
95
|
// #endregion
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { Reactive, ReactiveOptions, ReactiveState } from "../models.mjs";
|
|
2
|
-
//#region src/value/reactive.d.ts
|
|
3
|
-
export declare function reactive<Value, Item = Value>(value: Value, options?: ReactiveOptions<Item>): [Reactive<Value>, ReactiveState<Value, Item>];
|
|
4
|
-
//#endregion
|
package/dist/value/reactive.mjs
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
//#region src/value/reactive.ts
|
|
2
|
-
function reactive(value, options) {
|
|
3
|
-
const state = {
|
|
4
|
-
computeds: /* @__PURE__ */ new Set(),
|
|
5
|
-
effects: /* @__PURE__ */ new Set(),
|
|
6
|
-
equal: typeof options === "object" && typeof options?.equal === "function" ? options.equal : Object.is,
|
|
7
|
-
value
|
|
8
|
-
};
|
|
9
|
-
return [{
|
|
10
|
-
toJSON: () => state.value,
|
|
11
|
-
toString: () => String(state.value)
|
|
12
|
-
}, state];
|
|
13
|
-
}
|
|
14
|
-
//#endregion
|
|
15
|
-
export { reactive };
|
package/src/value/reactive.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type {Reactive, ReactiveOptions, ReactiveState} from '../models';
|
|
2
|
-
|
|
3
|
-
// #region Functions
|
|
4
|
-
|
|
5
|
-
export function reactive<Value, Item = Value>(
|
|
6
|
-
value: Value,
|
|
7
|
-
options?: ReactiveOptions<Item>,
|
|
8
|
-
): [Reactive<Value>, ReactiveState<Value, Item>] {
|
|
9
|
-
const state: ReactiveState<Value, Item> = {
|
|
10
|
-
computeds: new Set(),
|
|
11
|
-
effects: new Set(),
|
|
12
|
-
equal:
|
|
13
|
-
typeof options === 'object' && typeof options?.equal === 'function'
|
|
14
|
-
? options.equal
|
|
15
|
-
: Object.is,
|
|
16
|
-
value: value as Value,
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const instance = {
|
|
20
|
-
toJSON: () => state.value,
|
|
21
|
-
toString: () => String(state.value),
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
return [instance, state];
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// #endregion
|