@oscarpalmer/mora 0.16.0 → 0.18.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/package.json +1 -1
- package/src/helpers/is.ts +7 -1
- package/src/helpers/proxy.ts +72 -0
- package/src/helpers/value.ts +30 -32
- package/src/index.ts +1 -0
- package/src/subscription.ts +3 -3
- package/src/value/array.ts +21 -36
- package/src/value/computed.ts +10 -7
- package/src/value/reactive.ts +17 -4
- package/src/value/signal.ts +10 -7
- package/src/value/store.ts +90 -0
package/package.json
CHANGED
package/src/helpers/is.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type {ReactiveArray} from '../value/array';
|
|
|
4
4
|
import type {Computed} from '../value/computed';
|
|
5
5
|
import type {Reactive} from '../value/reactive';
|
|
6
6
|
import type {Signal} from '../value/signal';
|
|
7
|
+
import type {Store} from '../value/store';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Is the value a reactive array?
|
|
@@ -48,9 +49,14 @@ export function isSignal(value: unknown): value is Signal<unknown> {
|
|
|
48
49
|
return isMora<Signal<unknown>>(value, signalName);
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
export function isStore(value: unknown): value is Store<unknown> {
|
|
53
|
+
return isMora<Reactive<unknown>>(value, storeName);
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
export const arrayName = 'array';
|
|
52
57
|
export const computedName = 'computed';
|
|
53
58
|
export const effectName = 'effect';
|
|
54
59
|
export const signalName = 'signal';
|
|
60
|
+
export const storeName = 'store';
|
|
55
61
|
|
|
56
|
-
const reactiveNames = new Set([arrayName, computedName, signalName]);
|
|
62
|
+
const reactiveNames = new Set([arrayName, computedName, signalName, storeName]);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {isArrayOrPlainObject} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import type {ArrayOrPlainObject, PlainObject} from '@oscarpalmer/atoms/models';
|
|
3
|
+
import {startBatch, stopBatch} from '../batch';
|
|
4
|
+
import type {ReactiveState} from '../value/reactive';
|
|
5
|
+
import type {Signal} from '../value/signal';
|
|
6
|
+
import {emitValue} from './value';
|
|
7
|
+
|
|
8
|
+
export function setProxyValue(
|
|
9
|
+
proxy: ArrayOrPlainObject,
|
|
10
|
+
value: ArrayOrPlainObject,
|
|
11
|
+
): void {
|
|
12
|
+
startBatch();
|
|
13
|
+
|
|
14
|
+
const proxyKeys = Object.keys(proxy);
|
|
15
|
+
const valueKeys = Object.keys(value);
|
|
16
|
+
|
|
17
|
+
let {length} = proxyKeys;
|
|
18
|
+
|
|
19
|
+
for (let index = 0; index < length; index += 1) {
|
|
20
|
+
const key = proxyKeys[index];
|
|
21
|
+
|
|
22
|
+
(proxy as PlainObject)[key] = valueKeys.includes(key)
|
|
23
|
+
? (value as PlainObject)[key]
|
|
24
|
+
: undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
length = valueKeys.length;
|
|
28
|
+
|
|
29
|
+
for (let index = 0; index < length; index += 1) {
|
|
30
|
+
const key = valueKeys[index];
|
|
31
|
+
|
|
32
|
+
if (!proxyKeys.includes(key)) {
|
|
33
|
+
const keyedValue = (value as PlainObject)[key];
|
|
34
|
+
|
|
35
|
+
(proxy as PlainObject)[key] = keyedValue;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
stopBatch();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function setValueInProxy<Value extends ArrayOrPlainObject, Equal>(
|
|
43
|
+
target: Value,
|
|
44
|
+
property: PropertyKey,
|
|
45
|
+
value: unknown,
|
|
46
|
+
state: ReactiveState<Value, Equal>,
|
|
47
|
+
isArray: boolean,
|
|
48
|
+
length?: Signal<number>,
|
|
49
|
+
): boolean {
|
|
50
|
+
if (isArray) {
|
|
51
|
+
const isIndex = !Number.isNaN(Number(property));
|
|
52
|
+
const isLength = property === 'length';
|
|
53
|
+
|
|
54
|
+
if (!isIndex && !isLength) {
|
|
55
|
+
return Reflect.set(target, property, value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const previous = Reflect.get(target, property);
|
|
60
|
+
|
|
61
|
+
if (!state.equal(previous as never, value as never)) {
|
|
62
|
+
Reflect.set(target, property, value);
|
|
63
|
+
|
|
64
|
+
emitValue(state);
|
|
65
|
+
|
|
66
|
+
if (isArray) {
|
|
67
|
+
length?.set((target as unknown[]).length);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return true;
|
|
72
|
+
}
|
package/src/helpers/value.ts
CHANGED
|
@@ -3,11 +3,33 @@ import {activeEffect} from '../effect';
|
|
|
3
3
|
import {type InternalComputed, activeComputed} from '../value/computed';
|
|
4
4
|
import type {ReactiveState} from '../value/reactive';
|
|
5
5
|
|
|
6
|
-
export function
|
|
6
|
+
export function emitValue<Value>(state: ReactiveState<Value, never>): void {
|
|
7
|
+
for (const computed of state.computeds) {
|
|
8
|
+
(computed as unknown as InternalComputed).effect.dirty = true;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
for (const effect of state.effects) {
|
|
12
|
+
batchedHandlers.add(effect);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
for (const [, subscription] of state.subscriptions) {
|
|
16
|
+
batchedHandlers.add(subscription as never);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (batchDepth === 0) {
|
|
20
|
+
flushHandlers();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function equalArrays<Value>(
|
|
25
|
+
state: ReactiveState<Value[], Value>,
|
|
26
|
+
first: Value[],
|
|
27
|
+
second: Value[],
|
|
28
|
+
): boolean {
|
|
7
29
|
let {length} = first;
|
|
8
30
|
|
|
9
31
|
if (length !== second.length) {
|
|
10
|
-
return
|
|
32
|
+
return false;
|
|
11
33
|
}
|
|
12
34
|
|
|
13
35
|
let offset = 0;
|
|
@@ -17,8 +39,8 @@ export function differentArrays(first: unknown[], second: unknown[]): boolean {
|
|
|
17
39
|
offset = offset > 25 ? 25 : offset;
|
|
18
40
|
|
|
19
41
|
for (let index = 0; index < offset; index += 1) {
|
|
20
|
-
if (!
|
|
21
|
-
return
|
|
42
|
+
if (!state.equal(first[index], second[index])) {
|
|
43
|
+
return false;
|
|
22
44
|
}
|
|
23
45
|
}
|
|
24
46
|
}
|
|
@@ -26,39 +48,15 @@ export function differentArrays(first: unknown[], second: unknown[]): boolean {
|
|
|
26
48
|
length -= offset;
|
|
27
49
|
|
|
28
50
|
for (let index = offset; index < length; index += 1) {
|
|
29
|
-
if (!
|
|
30
|
-
return
|
|
51
|
+
if (!state.equal(first[index], second[index])) {
|
|
52
|
+
return false;
|
|
31
53
|
}
|
|
32
54
|
}
|
|
33
55
|
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function differentValues(first: unknown, second: unknown): boolean {
|
|
38
|
-
return Array.isArray(first) && Array.isArray(second)
|
|
39
|
-
? differentArrays(first, second)
|
|
40
|
-
: !Object.is(first, second);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function emitValue<Value>(state: ReactiveState<Value>): void {
|
|
44
|
-
for (const computed of state.computeds) {
|
|
45
|
-
(computed as unknown as InternalComputed).effect.dirty = true;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
for (const effect of state.effects) {
|
|
49
|
-
batchedHandlers.add(effect);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
for (const [, subscription] of state.subscriptions) {
|
|
53
|
-
batchedHandlers.add(subscription as never);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (batchDepth === 0) {
|
|
57
|
-
flushHandlers();
|
|
58
|
-
}
|
|
56
|
+
return true;
|
|
59
57
|
}
|
|
60
58
|
|
|
61
|
-
export function getValue<Value>(state: ReactiveState<Value>): Value {
|
|
59
|
+
export function getValue<Value>(state: ReactiveState<Value, never>): Value {
|
|
62
60
|
if (activeComputed != null) {
|
|
63
61
|
state.computeds.add(activeComputed);
|
|
64
62
|
}
|
package/src/index.ts
CHANGED
|
@@ -11,3 +11,4 @@ export {array, type ReactiveArray} from './value/array';
|
|
|
11
11
|
export {computed, type Computed} from './value/computed';
|
|
12
12
|
export type {Reactive} from './value/reactive';
|
|
13
13
|
export {signal, type Signal} from './value/signal';
|
|
14
|
+
export {store, type Store} from './value/store';
|
package/src/subscription.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type {ReactiveState} from './value/reactive';
|
|
|
3
3
|
|
|
4
4
|
export class Subscription<Value> {
|
|
5
5
|
constructor(
|
|
6
|
-
public state: ReactiveState<Value>,
|
|
6
|
+
public state: ReactiveState<Value, never>,
|
|
7
7
|
public callback: GenericCallback,
|
|
8
8
|
) {
|
|
9
9
|
callback(state.value);
|
|
@@ -18,7 +18,7 @@ export type Unsubscribe = () => void;
|
|
|
18
18
|
export function noop(): void {}
|
|
19
19
|
|
|
20
20
|
export function subscribe<Value>(
|
|
21
|
-
state: ReactiveState<Value>,
|
|
21
|
+
state: ReactiveState<Value, never>,
|
|
22
22
|
callback: (value: Value) => void,
|
|
23
23
|
): Unsubscribe {
|
|
24
24
|
if (typeof callback !== 'function' || state.subscriptions.has(callback)) {
|
|
@@ -33,7 +33,7 @@ export function subscribe<Value>(
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export function unsubscribe<Value>(
|
|
36
|
-
state: ReactiveState<Value>,
|
|
36
|
+
state: ReactiveState<Value, never>,
|
|
37
37
|
callback: (value: Value) => void,
|
|
38
38
|
): void {
|
|
39
39
|
const subscription = state.subscriptions.get(callback);
|
package/src/value/array.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {arrayName} from '../helpers/is';
|
|
2
|
-
import {
|
|
2
|
+
import {setValueInProxy} from '../helpers/proxy';
|
|
3
|
+
import {emitValue, equalArrays, getValue} from '../helpers/value';
|
|
3
4
|
import {type Computed, computed} from './computed';
|
|
4
|
-
import {Reactive, type ReactiveState} from './reactive';
|
|
5
|
+
import {Reactive, type ReactiveOptions, type ReactiveState} from './reactive';
|
|
5
6
|
import {type Signal, signal} from './signal';
|
|
6
7
|
|
|
7
|
-
export class ReactiveArray<Item> extends Reactive<Item[]> {
|
|
8
|
+
export class ReactiveArray<Item> extends Reactive<Item[], Item> {
|
|
8
9
|
#size = signal(0);
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -27,7 +28,7 @@ export class ReactiveArray<Item> extends Reactive<Item[]> {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
constructor(value: Item[]) {
|
|
31
|
+
constructor(value: Item[], options?: ReactiveOptions<Item>) {
|
|
31
32
|
super(
|
|
32
33
|
arrayName,
|
|
33
34
|
new Proxy(value, {
|
|
@@ -36,8 +37,16 @@ export class ReactiveArray<Item> extends Reactive<Item[]> {
|
|
|
36
37
|
? updateArray(property as string, target, this.state, this.#size)
|
|
37
38
|
: Reflect.get(target, property),
|
|
38
39
|
set: (target, property, value) =>
|
|
39
|
-
|
|
40
|
+
setValueInProxy(
|
|
41
|
+
target,
|
|
42
|
+
property,
|
|
43
|
+
value,
|
|
44
|
+
this.state,
|
|
45
|
+
true,
|
|
46
|
+
this.#size,
|
|
47
|
+
),
|
|
40
48
|
}),
|
|
49
|
+
options,
|
|
41
50
|
);
|
|
42
51
|
|
|
43
52
|
this.#size.set(value.length);
|
|
@@ -164,41 +173,17 @@ export class ReactiveArray<Item> extends Reactive<Item[]> {
|
|
|
164
173
|
/**
|
|
165
174
|
* Create a reactive array
|
|
166
175
|
*/
|
|
167
|
-
export function array<Item>(
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
target: Item[],
|
|
173
|
-
property: PropertyKey,
|
|
174
|
-
value: unknown,
|
|
175
|
-
state: ReactiveState<Item[]>,
|
|
176
|
-
length: Signal<number>,
|
|
177
|
-
): boolean {
|
|
178
|
-
const isIndex = !Number.isNaN(Number(property));
|
|
179
|
-
const isLength = property === 'length';
|
|
180
|
-
|
|
181
|
-
if (!isIndex && !isLength) {
|
|
182
|
-
return Reflect.set(target, property, value);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const previous = Reflect.get(target, property);
|
|
186
|
-
|
|
187
|
-
if (!Object.is(previous, value)) {
|
|
188
|
-
Reflect.set(target, property, value);
|
|
189
|
-
|
|
190
|
-
emitValue(state);
|
|
191
|
-
|
|
192
|
-
length.set(target.length);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return true;
|
|
176
|
+
export function array<Item>(
|
|
177
|
+
value: Item[],
|
|
178
|
+
options?: ReactiveOptions<Item>,
|
|
179
|
+
): ReactiveArray<Item> {
|
|
180
|
+
return new ReactiveArray(Array.isArray(value) ? value : [], options);
|
|
196
181
|
}
|
|
197
182
|
|
|
198
183
|
function updateArray<Item>(
|
|
199
184
|
type: string,
|
|
200
185
|
array: Item[],
|
|
201
|
-
state: ReactiveState<Item[]>,
|
|
186
|
+
state: ReactiveState<Item[], Item>,
|
|
202
187
|
length: Signal<number>,
|
|
203
188
|
): unknown {
|
|
204
189
|
const affectsLength = lengthAffectingMethods.has(type);
|
|
@@ -213,7 +198,7 @@ function updateArray<Item>(
|
|
|
213
198
|
if (
|
|
214
199
|
affectsLength
|
|
215
200
|
? array.length !== previousLength
|
|
216
|
-
:
|
|
201
|
+
: !equalArrays(state, previousArray, array)
|
|
217
202
|
) {
|
|
218
203
|
emitValue(state);
|
|
219
204
|
|
package/src/value/computed.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {batchDepth, batchedHandlers} from '../batch';
|
|
2
2
|
import {type Effect, activeEffect, effect, runEffect} from '../effect';
|
|
3
3
|
import {computedName} from '../helpers/is';
|
|
4
|
-
import {Reactive, type ReactiveState} from './reactive';
|
|
4
|
+
import {Reactive, type ReactiveOptions, type ReactiveState} from './reactive';
|
|
5
5
|
|
|
6
6
|
export type ComputedEffect = {
|
|
7
7
|
dirty: boolean;
|
|
@@ -10,7 +10,7 @@ export type ComputedEffect = {
|
|
|
10
10
|
|
|
11
11
|
export type InternalComputed = {
|
|
12
12
|
readonly effect: ComputedEffect;
|
|
13
|
-
readonly state: ReactiveState<unknown>;
|
|
13
|
+
readonly state: ReactiveState<unknown, unknown>;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export let activeComputed: Computed<unknown> | undefined;
|
|
@@ -21,8 +21,8 @@ export class Computed<Value> extends Reactive<Value> {
|
|
|
21
21
|
instance: undefined as never,
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
constructor(callback: () => Value) {
|
|
25
|
-
super(computedName, undefined as never);
|
|
24
|
+
constructor(callback: () => Value, options?: ReactiveOptions<Value>) {
|
|
25
|
+
super(computedName, undefined as never, options);
|
|
26
26
|
|
|
27
27
|
this.effect.instance = effect(() => {
|
|
28
28
|
if (this.effect.dirty) {
|
|
@@ -34,7 +34,7 @@ export class Computed<Value> extends Reactive<Value> {
|
|
|
34
34
|
|
|
35
35
|
activeComputed = previousComputed;
|
|
36
36
|
|
|
37
|
-
if (!
|
|
37
|
+
if (!this.state.equal(this.state.value, value)) {
|
|
38
38
|
this.state.value = value;
|
|
39
39
|
|
|
40
40
|
for (const computed of this.state.computeds) {
|
|
@@ -78,6 +78,9 @@ export class Computed<Value> extends Reactive<Value> {
|
|
|
78
78
|
/**
|
|
79
79
|
* Create a computed value
|
|
80
80
|
*/
|
|
81
|
-
export function computed<Value>(
|
|
82
|
-
|
|
81
|
+
export function computed<Value>(
|
|
82
|
+
callback: () => Value,
|
|
83
|
+
options?: ReactiveOptions<Value>,
|
|
84
|
+
): Computed<Value> {
|
|
85
|
+
return new Computed(callback, options);
|
|
83
86
|
}
|
package/src/value/reactive.ts
CHANGED
|
@@ -7,17 +7,22 @@ import {
|
|
|
7
7
|
} from '../subscription';
|
|
8
8
|
import type {Computed} from './computed';
|
|
9
9
|
|
|
10
|
-
export abstract class Reactive<Value> {
|
|
11
|
-
protected readonly state: ReactiveState<Value> = {
|
|
10
|
+
export abstract class Reactive<Value, Equal = Value> {
|
|
11
|
+
protected readonly state: ReactiveState<Value, Equal> = {
|
|
12
12
|
computeds: new Set(),
|
|
13
13
|
effects: new Set(),
|
|
14
|
+
equal: Object.is,
|
|
14
15
|
subscriptions: new Map(),
|
|
15
16
|
value: undefined as never,
|
|
16
17
|
};
|
|
17
18
|
|
|
18
|
-
constructor(name: string, value: Value) {
|
|
19
|
+
constructor(name: string, value: Value, options?: ReactiveOptions<Equal>) {
|
|
19
20
|
this.state.value = value;
|
|
20
21
|
|
|
22
|
+
if (typeof options === 'object' && typeof options.equal === 'function') {
|
|
23
|
+
this.state.equal = options.equal;
|
|
24
|
+
}
|
|
25
|
+
|
|
21
26
|
Object.defineProperty(this, '$mora', {
|
|
22
27
|
value: name,
|
|
23
28
|
});
|
|
@@ -64,9 +69,17 @@ export abstract class Reactive<Value> {
|
|
|
64
69
|
}
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
export type
|
|
72
|
+
export type ReactiveOptions<Value> = {
|
|
73
|
+
/**
|
|
74
|
+
* Method to compare values for equality
|
|
75
|
+
*/
|
|
76
|
+
equal?: (first: Value, second: Value) => boolean;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export type ReactiveState<Value, Equal> = {
|
|
68
80
|
computeds: Set<Computed<unknown>>;
|
|
69
81
|
effects: Set<Effect>;
|
|
82
|
+
equal: (first: Equal, second: Equal) => boolean;
|
|
70
83
|
subscriptions: Map<(value: Value) => void, Subscription<Value>>;
|
|
71
84
|
value: Value;
|
|
72
85
|
};
|
package/src/value/signal.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {signalName} from '../helpers/is';
|
|
2
|
-
import {
|
|
3
|
-
import {Reactive} from './reactive';
|
|
2
|
+
import {emitValue, getValue} from '../helpers/value';
|
|
3
|
+
import {Reactive, type ReactiveOptions} from './reactive';
|
|
4
4
|
|
|
5
5
|
export class Signal<Value> extends Reactive<Value> {
|
|
6
|
-
constructor(value: Value) {
|
|
7
|
-
super(signalName, value);
|
|
6
|
+
constructor(value: Value, options?: ReactiveOptions<Value>) {
|
|
7
|
+
super(signalName, value, options);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -18,7 +18,7 @@ export class Signal<Value> extends Reactive<Value> {
|
|
|
18
18
|
* Set the value
|
|
19
19
|
*/
|
|
20
20
|
set(value: Value): void {
|
|
21
|
-
if (
|
|
21
|
+
if (!this.state.equal(this.state.value, value)) {
|
|
22
22
|
this.state.value = value;
|
|
23
23
|
|
|
24
24
|
emitValue(this.state);
|
|
@@ -36,6 +36,9 @@ export class Signal<Value> extends Reactive<Value> {
|
|
|
36
36
|
/**
|
|
37
37
|
* Create a reactive value
|
|
38
38
|
*/
|
|
39
|
-
export function signal<Value>(
|
|
40
|
-
|
|
39
|
+
export function signal<Value>(
|
|
40
|
+
value: Value,
|
|
41
|
+
options?: ReactiveOptions<Value>,
|
|
42
|
+
): Signal<Value> {
|
|
43
|
+
return new Signal<Value>(value, options);
|
|
41
44
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import {isKey, isPlainObject} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import type {Key, PlainObject} from '@oscarpalmer/atoms/models';
|
|
3
|
+
import {storeName} from '../helpers/is';
|
|
4
|
+
import {setProxyValue, setValueInProxy} from '../helpers/proxy';
|
|
5
|
+
import {getValue} from '../helpers/value';
|
|
6
|
+
import {Reactive, type ReactiveOptions} from './reactive';
|
|
7
|
+
|
|
8
|
+
export class Store<Value extends PlainObject> extends Reactive<Value, Value> {
|
|
9
|
+
constructor(value: Value, options?: ReactiveOptions<Value>) {
|
|
10
|
+
super(
|
|
11
|
+
storeName,
|
|
12
|
+
new Proxy(value, {
|
|
13
|
+
set: (target, property, value) =>
|
|
14
|
+
setValueInProxy(target, property, value, this.state, false),
|
|
15
|
+
}),
|
|
16
|
+
options,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @inheritdoc
|
|
22
|
+
*/
|
|
23
|
+
get(): Value;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get a value by key _(without reactivity)_
|
|
27
|
+
*/
|
|
28
|
+
get(key: keyof Value): Value[keyof Value];
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get a value by key _(without reactivity)_
|
|
32
|
+
*/
|
|
33
|
+
get(key: Key): unknown;
|
|
34
|
+
|
|
35
|
+
get(key?: unknown): unknown {
|
|
36
|
+
return isKey(key) ? this.state.value[key] : getValue(this.state);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get the value _(without reactivity)_
|
|
41
|
+
*/
|
|
42
|
+
peek(): Value;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get a value by key _(without reactivity)_
|
|
46
|
+
*/
|
|
47
|
+
peek(key: keyof Value): Value[keyof Value];
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get a value by key _(without reactivity)_
|
|
51
|
+
*/
|
|
52
|
+
peek(key: Key): unknown;
|
|
53
|
+
|
|
54
|
+
peek(key?: unknown): unknown {
|
|
55
|
+
return isKey(key) ? this.state.value[key] : {...this.state.value};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Set the value
|
|
60
|
+
*/
|
|
61
|
+
set(value?: Value): void;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Set a value by key
|
|
65
|
+
*/
|
|
66
|
+
set(key: keyof Value, value: Value[keyof Value]): void;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Set a value by key
|
|
70
|
+
*/
|
|
71
|
+
set(key: Key, value: unknown): void;
|
|
72
|
+
|
|
73
|
+
set(first?: unknown, second?: unknown): void {
|
|
74
|
+
if (isKey(first)) {
|
|
75
|
+
(this.state.value as PlainObject)[first] = second;
|
|
76
|
+
} else if (first == null || isPlainObject(first)) {
|
|
77
|
+
setProxyValue(this.state.value, first ?? {});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Create a reactive store
|
|
84
|
+
*/
|
|
85
|
+
export function store<Value extends PlainObject>(
|
|
86
|
+
value: Value,
|
|
87
|
+
options?: ReactiveOptions<Value>,
|
|
88
|
+
): Store<Value> {
|
|
89
|
+
return new Store((isPlainObject(value) ? value : {}) as Value, options);
|
|
90
|
+
}
|