@oscarpalmer/mora 0.13.0 → 0.15.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 +2 -2
- package/dist/batch.js +1 -1
- package/dist/effect.cjs +2 -1
- package/dist/effect.js +2 -1
- package/dist/helpers/emit.cjs +42 -0
- package/dist/helpers/emit.js +42 -0
- package/dist/helpers/is.cjs +34 -0
- package/dist/helpers/is.js +34 -0
- package/dist/helpers/value.cjs +22 -0
- package/dist/helpers/value.js +22 -0
- package/dist/index.cjs +12 -11
- package/dist/index.js +5 -4
- package/dist/mora.full.js +200 -140
- package/dist/value/array.cjs +161 -0
- package/dist/{array.js → value/array.js} +62 -31
- package/dist/{computed.cjs → value/computed.cjs} +6 -5
- package/dist/{computed.js → value/computed.js} +4 -3
- package/dist/{reactive.cjs → value/reactive.cjs} +1 -1
- package/dist/{reactive.js → value/reactive.js} +1 -1
- package/dist/value/signal.cjs +33 -0
- package/dist/{signal.js → value/signal.js} +3 -2
- package/package.json +1 -1
- package/src/batch.ts +1 -1
- package/src/effect.ts +12 -11
- package/src/helpers/emit.ts +52 -0
- package/src/helpers/is.ts +56 -0
- package/src/helpers/value.ts +27 -0
- package/src/index.ts +11 -5
- package/src/subscription.ts +1 -1
- package/src/{array.ts → value/array.ts} +75 -41
- package/src/{computed.ts → value/computed.ts} +4 -3
- package/src/{reactive.ts → value/reactive.ts} +3 -3
- package/src/{signal.ts → value/signal.ts} +3 -2
- package/types/batch.d.cts +9 -9
- package/types/helpers/emit.d.cts +63 -0
- package/types/helpers/emit.d.ts +3 -0
- package/types/{is.d.cts → helpers/is.d.cts} +85 -9
- package/types/helpers/is.d.ts +26 -0
- package/types/{value.d.cts → helpers/value.d.cts} +9 -10
- package/types/{value.d.ts → helpers/value.d.ts} +1 -2
- package/types/index.d.cts +74 -38
- package/types/index.d.ts +5 -5
- package/types/subscription.d.cts +12 -12
- package/types/subscription.d.ts +1 -1
- package/types/{array.d.cts → value/array.d.cts} +41 -9
- package/types/value/array.d.ts +74 -0
- package/types/{computed.d.ts → value/computed.d.ts} +1 -1
- package/types/{reactive.d.ts → value/reactive.d.ts} +2 -2
- package/dist/array.cjs +0 -130
- package/dist/is.cjs +0 -21
- package/dist/is.js +0 -21
- package/dist/signal.cjs +0 -32
- package/dist/value.cjs +0 -38
- package/dist/value.js +0 -38
- package/src/is.ts +0 -39
- package/src/value.ts +0 -47
- package/types/array.d.ts +0 -41
- package/types/is.d.ts +0 -17
- package/types/{computed.d.cts → value/computed.d.cts} +9 -9
- package/types/{reactive.d.cts → value/reactive.d.cts} +9 -9
- package/types/{signal.d.cts → value/signal.d.cts} +9 -9
- /package/types/{signal.d.ts → value/signal.d.ts} +0 -0
|
@@ -5,13 +5,16 @@ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot
|
|
|
5
5
|
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
6
6
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
7
7
|
var _size;
|
|
8
|
+
import { emitValue, emitArrayChanges } from "../helpers/emit.js";
|
|
9
|
+
import { arrayName } from "../helpers/is.js";
|
|
10
|
+
import { getValue } from "../helpers/value.js";
|
|
11
|
+
import { computed } from "./computed.js";
|
|
8
12
|
import { Reactive } from "./reactive.js";
|
|
9
13
|
import { signal } from "./signal.js";
|
|
10
|
-
import { getValue, emitValue } from "./value.js";
|
|
11
14
|
class ReactiveArray extends Reactive {
|
|
12
15
|
constructor(value) {
|
|
13
16
|
super(
|
|
14
|
-
|
|
17
|
+
arrayName,
|
|
15
18
|
new Proxy(value, {
|
|
16
19
|
get: (target, property) => updateMethods.has(property) ? updateArray(property, target, this.state, __privateGet(this, _size)) : Reflect.get(target, property),
|
|
17
20
|
set: (target, property, value2) => setValue(target, property, value2, this.state, __privateGet(this, _size))
|
|
@@ -34,15 +37,45 @@ class ReactiveArray extends Reactive {
|
|
|
34
37
|
this.get().length = value;
|
|
35
38
|
}
|
|
36
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Get an indexed item
|
|
42
|
+
*/
|
|
43
|
+
at(index) {
|
|
44
|
+
return this.get().at(index);
|
|
45
|
+
}
|
|
37
46
|
/**
|
|
38
47
|
* @inheritdoc
|
|
39
48
|
*/
|
|
40
49
|
get() {
|
|
41
50
|
return getValue(this.state);
|
|
42
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Create a computed, filtered array
|
|
54
|
+
*/
|
|
55
|
+
filter(callback) {
|
|
56
|
+
return computed(() => this.get().filter(callback));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Create a computed, mapped array
|
|
60
|
+
*/
|
|
61
|
+
map(callback) {
|
|
62
|
+
return computed(() => this.get().map(callback));
|
|
63
|
+
}
|
|
43
64
|
peek(length) {
|
|
44
65
|
return length === true ? __privateGet(this, _size).peek() : [...this.state.value];
|
|
45
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Remove and return the last item of the array
|
|
69
|
+
*/
|
|
70
|
+
pop() {
|
|
71
|
+
return this.state.value.pop();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Add items to the end of the array
|
|
75
|
+
*/
|
|
76
|
+
push(...items) {
|
|
77
|
+
return this.state.value.push(...items);
|
|
78
|
+
}
|
|
46
79
|
set(first, second) {
|
|
47
80
|
if (Array.isArray(first)) {
|
|
48
81
|
this.state.value.splice(0, this.state.value.length, ...first);
|
|
@@ -52,34 +85,33 @@ class ReactiveArray extends Reactive {
|
|
|
52
85
|
this.state.value[first] = second;
|
|
53
86
|
}
|
|
54
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Remove and return the first item of the array
|
|
90
|
+
*/
|
|
91
|
+
shift() {
|
|
92
|
+
return this.state.value.shift();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Remove and return items from the array _(and optionally add new items)_
|
|
96
|
+
*/
|
|
97
|
+
splice(from, to, ...items) {
|
|
98
|
+
return this.state.value.splice(
|
|
99
|
+
from,
|
|
100
|
+
to ?? this.state.value.length,
|
|
101
|
+
...items
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Add items to the beginning of the array
|
|
106
|
+
*/
|
|
107
|
+
unshift(...items) {
|
|
108
|
+
return this.state.value.unshift(...items);
|
|
109
|
+
}
|
|
55
110
|
}
|
|
56
111
|
_size = new WeakMap();
|
|
57
112
|
function array(value) {
|
|
58
113
|
return new ReactiveArray(Array.isArray(value) ? value : []);
|
|
59
114
|
}
|
|
60
|
-
function emit(first, second) {
|
|
61
|
-
let { length } = first;
|
|
62
|
-
if (length !== second.length) {
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
let offset = 0;
|
|
66
|
-
if (length >= 100) {
|
|
67
|
-
offset = Math.round(length / 10);
|
|
68
|
-
offset = offset > 25 ? 25 : offset;
|
|
69
|
-
for (let index = 0; index < offset; index += 1) {
|
|
70
|
-
if (!Object.is(first[index], second[index])) {
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
length -= offset;
|
|
76
|
-
for (let index = offset; index < length; index += 1) {
|
|
77
|
-
if (!Object.is(first[index], second[index])) {
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
115
|
function setValue(target, property, value, state, length) {
|
|
84
116
|
const isIndex = !Number.isNaN(Number(property));
|
|
85
117
|
const isLength = property === "length";
|
|
@@ -87,12 +119,11 @@ function setValue(target, property, value, state, length) {
|
|
|
87
119
|
return Reflect.set(target, property, value);
|
|
88
120
|
}
|
|
89
121
|
const previous = Reflect.get(target, property);
|
|
90
|
-
if (Object.is(previous, value)) {
|
|
91
|
-
|
|
122
|
+
if (!Object.is(previous, value)) {
|
|
123
|
+
Reflect.set(target, property, value);
|
|
124
|
+
emitValue(state);
|
|
125
|
+
length.set(target.length);
|
|
92
126
|
}
|
|
93
|
-
Reflect.set(target, property, value);
|
|
94
|
-
emitValue(state);
|
|
95
|
-
length.set(target.length);
|
|
96
127
|
return true;
|
|
97
128
|
}
|
|
98
129
|
function updateArray(type, array2, state, length) {
|
|
@@ -103,7 +134,7 @@ function updateArray(type, array2, state, length) {
|
|
|
103
134
|
const result = array2[type](
|
|
104
135
|
...args
|
|
105
136
|
);
|
|
106
|
-
if (affectsLength ? array2.length !== previousLength :
|
|
137
|
+
if (affectsLength ? array2.length !== previousLength : emitArrayChanges(previousArray, array2)) {
|
|
107
138
|
emitValue(state);
|
|
108
139
|
length.set(array2.length);
|
|
109
140
|
}
|
|
@@ -3,13 +3,14 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
6
|
-
const batch = require("
|
|
7
|
-
const effect = require("
|
|
8
|
-
const
|
|
6
|
+
const batch = require("../batch.cjs");
|
|
7
|
+
const effect = require("../effect.cjs");
|
|
8
|
+
const helpers_is = require("../helpers/is.cjs");
|
|
9
|
+
const value_reactive = require("./reactive.cjs");
|
|
9
10
|
exports.activeComputed = void 0;
|
|
10
|
-
class Computed extends
|
|
11
|
+
class Computed extends value_reactive.Reactive {
|
|
11
12
|
constructor(callback) {
|
|
12
|
-
super(
|
|
13
|
+
super(helpers_is.computedName, void 0);
|
|
13
14
|
__publicField(this, "effect", {
|
|
14
15
|
dirty: true,
|
|
15
16
|
instance: void 0
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import { batchedHandlers, batchDepth } from "
|
|
5
|
-
import { effect, activeEffect, runEffect } from "
|
|
4
|
+
import { batchedHandlers, batchDepth } from "../batch.js";
|
|
5
|
+
import { effect, activeEffect, runEffect } from "../effect.js";
|
|
6
|
+
import { computedName } from "../helpers/is.js";
|
|
6
7
|
import { Reactive } from "./reactive.js";
|
|
7
8
|
let activeComputed;
|
|
8
9
|
class Computed extends Reactive {
|
|
9
10
|
constructor(callback) {
|
|
10
|
-
super(
|
|
11
|
+
super(computedName, void 0);
|
|
11
12
|
__publicField(this, "effect", {
|
|
12
13
|
dirty: true,
|
|
13
14
|
instance: void 0
|
|
@@ -3,7 +3,7 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
6
|
-
const subscription = require("
|
|
6
|
+
const subscription = require("../subscription.cjs");
|
|
7
7
|
class Reactive {
|
|
8
8
|
constructor(name, value) {
|
|
9
9
|
__publicField(this, "state", {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import { subscribe, unsubscribe } from "
|
|
4
|
+
import { subscribe, unsubscribe } from "../subscription.js";
|
|
5
5
|
class Reactive {
|
|
6
6
|
constructor(name, value) {
|
|
7
7
|
__publicField(this, "state", {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const helpers_is = require("../helpers/is.cjs");
|
|
4
|
+
const helpers_value = require("../helpers/value.cjs");
|
|
5
|
+
const value_reactive = require("./reactive.cjs");
|
|
6
|
+
class Signal extends value_reactive.Reactive {
|
|
7
|
+
constructor(value) {
|
|
8
|
+
super(helpers_is.signalName, value);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* @inheritdoc
|
|
12
|
+
*/
|
|
13
|
+
get() {
|
|
14
|
+
return helpers_value.getValue(this.state);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Set the value
|
|
18
|
+
*/
|
|
19
|
+
set(value) {
|
|
20
|
+
helpers_value.setValue(this.state, value);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Update the value
|
|
24
|
+
*/
|
|
25
|
+
update(callback) {
|
|
26
|
+
this.set(callback(this.state.value));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function signal(value) {
|
|
30
|
+
return new Signal(value);
|
|
31
|
+
}
|
|
32
|
+
exports.Signal = Signal;
|
|
33
|
+
exports.signal = signal;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { signalName } from "../helpers/is.js";
|
|
2
|
+
import { getValue, setValue } from "../helpers/value.js";
|
|
1
3
|
import { Reactive } from "./reactive.js";
|
|
2
|
-
import { getValue, setValue } from "./value.js";
|
|
3
4
|
class Signal extends Reactive {
|
|
4
5
|
constructor(value) {
|
|
5
|
-
super(
|
|
6
|
+
super(signalName, value);
|
|
6
7
|
}
|
|
7
8
|
/**
|
|
8
9
|
* @inheritdoc
|
package/package.json
CHANGED
package/src/batch.ts
CHANGED
package/src/effect.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import {effectName} from './helpers/is';
|
|
2
3
|
|
|
3
4
|
type EffectState = {
|
|
4
5
|
callback: GenericCallback;
|
|
@@ -9,22 +10,22 @@ type InternalEffect = {
|
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
export class Effect {
|
|
12
|
-
|
|
13
|
+
private declare readonly $mora: string;
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
private declare readonly state: EffectState;
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
constructor(callback: GenericCallback) {
|
|
18
|
+
Object.defineProperty(this, '$mora', {
|
|
19
|
+
value: effectName,
|
|
20
|
+
});
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
this.state = {
|
|
23
|
+
callback,
|
|
24
|
+
};
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
}
|
|
26
|
+
runEffect(this);
|
|
27
27
|
}
|
|
28
|
+
}
|
|
28
29
|
|
|
29
30
|
export function runEffect(effect: Effect): void {
|
|
30
31
|
const previousEffect = activeEffect;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {batchDepth, batchedHandlers, flushEffects} from '../batch';
|
|
2
|
+
import type {InternalComputed} from '../value/computed';
|
|
3
|
+
import type {ReactiveState} from '../value/reactive';
|
|
4
|
+
|
|
5
|
+
export function emitArrayChanges(first: unknown[], second: unknown[]): boolean {
|
|
6
|
+
let {length} = first;
|
|
7
|
+
|
|
8
|
+
if (length !== second.length) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let offset = 0;
|
|
13
|
+
|
|
14
|
+
if (length >= 100) {
|
|
15
|
+
offset = Math.round(length / 10);
|
|
16
|
+
offset = offset > 25 ? 25 : offset;
|
|
17
|
+
|
|
18
|
+
for (let index = 0; index < offset; index += 1) {
|
|
19
|
+
if (!Object.is(first[index], second[index])) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
length -= offset;
|
|
26
|
+
|
|
27
|
+
for (let index = offset; index < length; index += 1) {
|
|
28
|
+
if (!Object.is(first[index], second[index])) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function emitValue<Value>(state: ReactiveState<Value>): void {
|
|
37
|
+
for (const computed of state.computeds) {
|
|
38
|
+
(computed as unknown as InternalComputed).effect.dirty = true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (const effect of state.effects) {
|
|
42
|
+
batchedHandlers.add(effect);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (const [, subscription] of state.subscriptions) {
|
|
46
|
+
batchedHandlers.add(subscription as never);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (batchDepth === 0) {
|
|
50
|
+
flushEffects();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type {PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import type {Effect} from '../effect';
|
|
3
|
+
import type {ReactiveArray} from '../value/array';
|
|
4
|
+
import type {Computed} from '../value/computed';
|
|
5
|
+
import type {Reactive} from '../value/reactive';
|
|
6
|
+
import {signal, type Signal} from '../value/signal';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Is the value a reactive array?
|
|
10
|
+
*/
|
|
11
|
+
export function isArray(value: unknown): value is ReactiveArray<unknown> {
|
|
12
|
+
return isMora<ReactiveArray<unknown>>(value, arrayName);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Is the value a computed signal?
|
|
17
|
+
*/
|
|
18
|
+
export function isComputed(value: unknown): value is Computed<unknown> {
|
|
19
|
+
return isMora<Computed<unknown>>(value, computedName);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Is the value an effect?
|
|
24
|
+
*/
|
|
25
|
+
export function isEffect(value: unknown): value is Effect {
|
|
26
|
+
return isMora<Effect>(value, effectName);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isMora<T>(value: unknown, name: string | Set<string>): value is T {
|
|
30
|
+
return (
|
|
31
|
+
typeof value === 'object' &&
|
|
32
|
+
value != null &&
|
|
33
|
+
'$mora' in value &&
|
|
34
|
+
(typeof name === 'string'
|
|
35
|
+
? (value as PlainObject).$mora === name
|
|
36
|
+
: name.has((value as PlainObject).$mora as never))
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function isReactive(value: unknown): value is Reactive<unknown> {
|
|
41
|
+
return isMora<Reactive<unknown>>(value, reactiveNames);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Is the value a signal?
|
|
46
|
+
*/
|
|
47
|
+
export function isSignal(value: unknown): value is Signal<unknown> {
|
|
48
|
+
return isMora<Signal<unknown>>(value, signalName);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const arrayName = 'array';
|
|
52
|
+
export const computedName = 'computed';
|
|
53
|
+
export const effectName = 'effect';
|
|
54
|
+
export const signalName = 'signal';
|
|
55
|
+
|
|
56
|
+
const reactiveNames = new Set([arrayName, computedName, signalName]);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {activeEffect} from '../effect';
|
|
2
|
+
import {activeComputed} from '../value/computed';
|
|
3
|
+
import type {ReactiveState} from '../value/reactive';
|
|
4
|
+
import {emitValue} from './emit';
|
|
5
|
+
|
|
6
|
+
export function getValue<Value>(state: ReactiveState<Value>): Value {
|
|
7
|
+
if (activeComputed != null) {
|
|
8
|
+
state.computeds.add(activeComputed);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (activeEffect != null) {
|
|
12
|
+
state.effects.add(activeEffect);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return state.value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function setValue<Value>(
|
|
19
|
+
state: ReactiveState<Value>,
|
|
20
|
+
value: Value,
|
|
21
|
+
): void {
|
|
22
|
+
if (!Object.is(state.value, value)) {
|
|
23
|
+
state.value = value;
|
|
24
|
+
|
|
25
|
+
emitValue(state);
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
export {array, type ReactiveArray} from './array';
|
|
2
1
|
export {startBatch, stopBatch} from './batch';
|
|
3
|
-
export {computed, type Computed} from './computed';
|
|
4
2
|
export {effect, type Effect} from './effect';
|
|
5
|
-
export {
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
export {
|
|
4
|
+
isArray,
|
|
5
|
+
isComputed,
|
|
6
|
+
isEffect,
|
|
7
|
+
isReactive,
|
|
8
|
+
isSignal,
|
|
9
|
+
} from './helpers/is';
|
|
10
|
+
export {array, type ReactiveArray} from './value/array';
|
|
11
|
+
export {computed, type Computed} from './value/computed';
|
|
12
|
+
export type {Reactive} from './value/reactive';
|
|
13
|
+
export {signal, type Signal} from './value/signal';
|
package/src/subscription.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import {emitArrayChanges, emitValue} from '../helpers/emit';
|
|
2
|
+
import {arrayName} from '../helpers/is';
|
|
3
|
+
import {getValue} from '../helpers/value';
|
|
4
|
+
import {type Computed, computed} from './computed';
|
|
1
5
|
import {Reactive, type ReactiveState} from './reactive';
|
|
2
6
|
import {type Signal, signal} from './signal';
|
|
3
|
-
import {emitValue, getValue} from './value';
|
|
4
7
|
|
|
5
8
|
export class ReactiveArray<Item> extends Reactive<Item[]> {
|
|
6
9
|
#size = signal(0);
|
|
@@ -27,7 +30,7 @@ export class ReactiveArray<Item> extends Reactive<Item[]> {
|
|
|
27
30
|
|
|
28
31
|
constructor(value: Item[]) {
|
|
29
32
|
super(
|
|
30
|
-
|
|
33
|
+
arrayName,
|
|
31
34
|
new Proxy(value, {
|
|
32
35
|
get: (target, property) =>
|
|
33
36
|
updateMethods.has(property as string)
|
|
@@ -41,6 +44,13 @@ export class ReactiveArray<Item> extends Reactive<Item[]> {
|
|
|
41
44
|
this.#size.set(value.length);
|
|
42
45
|
}
|
|
43
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Get an indexed item
|
|
49
|
+
*/
|
|
50
|
+
at(index: number): Item | undefined {
|
|
51
|
+
return this.get().at(index);
|
|
52
|
+
}
|
|
53
|
+
|
|
44
54
|
/**
|
|
45
55
|
* @inheritdoc
|
|
46
56
|
*/
|
|
@@ -48,6 +58,24 @@ export class ReactiveArray<Item> extends Reactive<Item[]> {
|
|
|
48
58
|
return getValue(this.state);
|
|
49
59
|
}
|
|
50
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Create a computed, filtered array
|
|
63
|
+
*/
|
|
64
|
+
filter(
|
|
65
|
+
callback: (item: Item, index: number, array: Item[]) => boolean,
|
|
66
|
+
): Computed<Item[]> {
|
|
67
|
+
return computed(() => this.get().filter(callback));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Create a computed, mapped array
|
|
72
|
+
*/
|
|
73
|
+
map<Mapped>(
|
|
74
|
+
callback: (item: Item, index: number, array: Item[]) => Mapped,
|
|
75
|
+
): Computed<Mapped[]> {
|
|
76
|
+
return computed(() => this.get().map(callback));
|
|
77
|
+
}
|
|
78
|
+
|
|
51
79
|
/**
|
|
52
80
|
* @inheritdoc
|
|
53
81
|
*/
|
|
@@ -62,6 +90,20 @@ export class ReactiveArray<Item> extends Reactive<Item[]> {
|
|
|
62
90
|
return length === true ? this.#size.peek() : [...this.state.value];
|
|
63
91
|
}
|
|
64
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Remove and return the last item of the array
|
|
95
|
+
*/
|
|
96
|
+
pop(): Item | undefined {
|
|
97
|
+
return this.state.value.pop();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Add items to the end of the array
|
|
102
|
+
*/
|
|
103
|
+
push(...items: Item[]): number {
|
|
104
|
+
return this.state.value.push(...items);
|
|
105
|
+
}
|
|
106
|
+
|
|
65
107
|
/**
|
|
66
108
|
* Set the value
|
|
67
109
|
*/
|
|
@@ -86,44 +128,38 @@ export class ReactiveArray<Item> extends Reactive<Item[]> {
|
|
|
86
128
|
this.state.value[first] = second as Item;
|
|
87
129
|
}
|
|
88
130
|
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Create a reactive array
|
|
93
|
-
*/
|
|
94
|
-
export function array<Item>(value: Item[]): ReactiveArray<Item> {
|
|
95
|
-
return new ReactiveArray(Array.isArray(value) ? value : []);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function emit(first: unknown[], second: unknown[]): boolean {
|
|
99
|
-
let {length} = first;
|
|
100
131
|
|
|
101
|
-
|
|
102
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Remove and return the first item of the array
|
|
134
|
+
*/
|
|
135
|
+
shift(): Item | undefined {
|
|
136
|
+
return this.state.value.shift();
|
|
103
137
|
}
|
|
104
138
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
}
|
|
139
|
+
/**
|
|
140
|
+
* Remove and return items from the array _(and optionally add new items)_
|
|
141
|
+
*/
|
|
142
|
+
splice(from: number, to?: number, ...items: Item[]): Item[] {
|
|
143
|
+
return this.state.value.splice(
|
|
144
|
+
from,
|
|
145
|
+
to ?? this.state.value.length,
|
|
146
|
+
...items,
|
|
147
|
+
);
|
|
116
148
|
}
|
|
117
149
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
150
|
+
/**
|
|
151
|
+
* Add items to the beginning of the array
|
|
152
|
+
*/
|
|
153
|
+
unshift(...items: Item[]): number {
|
|
154
|
+
return this.state.value.unshift(...items);
|
|
124
155
|
}
|
|
156
|
+
}
|
|
125
157
|
|
|
126
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Create a reactive array
|
|
160
|
+
*/
|
|
161
|
+
export function array<Item>(value: Item[]): ReactiveArray<Item> {
|
|
162
|
+
return new ReactiveArray(Array.isArray(value) ? value : []);
|
|
127
163
|
}
|
|
128
164
|
|
|
129
165
|
function setValue<Item>(
|
|
@@ -142,15 +178,13 @@ function setValue<Item>(
|
|
|
142
178
|
|
|
143
179
|
const previous = Reflect.get(target, property);
|
|
144
180
|
|
|
145
|
-
if (Object.is(previous, value)) {
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
Reflect.set(target, property, value);
|
|
181
|
+
if (!Object.is(previous, value)) {
|
|
182
|
+
Reflect.set(target, property, value);
|
|
150
183
|
|
|
151
|
-
|
|
184
|
+
emitValue(state);
|
|
152
185
|
|
|
153
|
-
|
|
186
|
+
length.set(target.length);
|
|
187
|
+
}
|
|
154
188
|
|
|
155
189
|
return true;
|
|
156
190
|
}
|
|
@@ -173,7 +207,7 @@ function updateArray<Item>(
|
|
|
173
207
|
if (
|
|
174
208
|
affectsLength
|
|
175
209
|
? array.length !== previousLength
|
|
176
|
-
:
|
|
210
|
+
: emitArrayChanges(previousArray, array)
|
|
177
211
|
) {
|
|
178
212
|
emitValue(state);
|
|
179
213
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {batchDepth, batchedHandlers} from '
|
|
2
|
-
import {type Effect, activeEffect, effect, runEffect} from '
|
|
1
|
+
import {batchDepth, batchedHandlers} from '../batch';
|
|
2
|
+
import {type Effect, activeEffect, effect, runEffect} from '../effect';
|
|
3
|
+
import {computedName} from '../helpers/is';
|
|
3
4
|
import {Reactive, type ReactiveState} from './reactive';
|
|
4
5
|
|
|
5
6
|
type ComputedEffect = {
|
|
@@ -21,7 +22,7 @@ export class Computed<Value> extends Reactive<Value> {
|
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
constructor(callback: () => Value) {
|
|
24
|
-
super(
|
|
25
|
+
super(computedName, undefined as never);
|
|
25
26
|
|
|
26
27
|
this.effect.instance = effect(() => {
|
|
27
28
|
if (this.effect.dirty) {
|