@oscarpalmer/mora 0.15.0 → 0.17.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.
Files changed (44) hide show
  1. package/dist/batch.cjs +3 -3
  2. package/dist/batch.js +3 -3
  3. package/dist/helpers/value.cjs +44 -8
  4. package/dist/helpers/value.js +45 -9
  5. package/dist/mora.full.js +75 -64
  6. package/dist/value/array.cjs +15 -9
  7. package/dist/value/array.js +14 -8
  8. package/dist/value/computed.cjs +6 -6
  9. package/dist/value/computed.js +6 -6
  10. package/dist/value/reactive.cjs +5 -1
  11. package/dist/value/reactive.js +5 -1
  12. package/dist/value/signal.cjs +8 -5
  13. package/dist/value/signal.js +9 -6
  14. package/package.json +3 -3
  15. package/src/batch.ts +2 -2
  16. package/src/helpers/is.ts +1 -1
  17. package/src/helpers/value.ts +66 -14
  18. package/src/subscription.ts +3 -3
  19. package/src/value/array.ts +22 -12
  20. package/src/value/computed.ts +12 -9
  21. package/src/value/reactive.ts +17 -4
  22. package/src/value/signal.ts +14 -7
  23. package/types/batch.d.cts +15 -8
  24. package/types/batch.d.ts +1 -1
  25. package/types/helpers/is.d.cts +21 -10
  26. package/types/helpers/is.d.ts +1 -1
  27. package/types/helpers/value.d.cts +18 -9
  28. package/types/helpers/value.d.ts +4 -2
  29. package/types/index.d.cts +24 -13
  30. package/types/subscription.d.cts +16 -9
  31. package/types/subscription.d.ts +4 -4
  32. package/types/value/array.d.cts +21 -10
  33. package/types/value/array.d.ts +8 -4
  34. package/types/value/computed.d.cts +16 -9
  35. package/types/value/computed.d.ts +5 -6
  36. package/types/value/reactive.d.cts +14 -7
  37. package/types/value/reactive.d.ts +11 -4
  38. package/types/value/signal.d.cts +16 -9
  39. package/types/value/signal.d.ts +3 -3
  40. package/dist/helpers/emit.cjs +0 -42
  41. package/dist/helpers/emit.js +0 -42
  42. package/src/helpers/emit.ts +0 -52
  43. package/types/helpers/emit.d.cts +0 -63
  44. package/types/helpers/emit.d.ts +0 -3
@@ -4,8 +4,8 @@ const helpers_is = require("../helpers/is.cjs");
4
4
  const helpers_value = require("../helpers/value.cjs");
5
5
  const value_reactive = require("./reactive.cjs");
6
6
  class Signal extends value_reactive.Reactive {
7
- constructor(value) {
8
- super(helpers_is.signalName, value);
7
+ constructor(value, options) {
8
+ super(helpers_is.signalName, value, options);
9
9
  }
10
10
  /**
11
11
  * @inheritdoc
@@ -17,7 +17,10 @@ class Signal extends value_reactive.Reactive {
17
17
  * Set the value
18
18
  */
19
19
  set(value) {
20
- helpers_value.setValue(this.state, value);
20
+ if (helpers_value.differentValues(this.state, this.state.value, value)) {
21
+ this.state.value = value;
22
+ helpers_value.emitValue(this.state);
23
+ }
21
24
  }
22
25
  /**
23
26
  * Update the value
@@ -26,8 +29,8 @@ class Signal extends value_reactive.Reactive {
26
29
  this.set(callback(this.state.value));
27
30
  }
28
31
  }
29
- function signal(value) {
30
- return new Signal(value);
32
+ function signal(value, options) {
33
+ return new Signal(value, options);
31
34
  }
32
35
  exports.Signal = Signal;
33
36
  exports.signal = signal;
@@ -1,9 +1,9 @@
1
1
  import { signalName } from "../helpers/is.js";
2
- import { getValue, setValue } from "../helpers/value.js";
2
+ import { getValue, differentValues, emitValue } from "../helpers/value.js";
3
3
  import { Reactive } from "./reactive.js";
4
4
  class Signal extends Reactive {
5
- constructor(value) {
6
- super(signalName, value);
5
+ constructor(value, options) {
6
+ super(signalName, value, options);
7
7
  }
8
8
  /**
9
9
  * @inheritdoc
@@ -15,7 +15,10 @@ class Signal extends Reactive {
15
15
  * Set the value
16
16
  */
17
17
  set(value) {
18
- setValue(this.state, value);
18
+ if (differentValues(this.state, this.state.value, value)) {
19
+ this.state.value = value;
20
+ emitValue(this.state);
21
+ }
19
22
  }
20
23
  /**
21
24
  * Update the value
@@ -24,8 +27,8 @@ class Signal extends Reactive {
24
27
  this.set(callback(this.state.value));
25
28
  }
26
29
  }
27
- function signal(value) {
28
- return new Signal(value);
30
+ function signal(value, options) {
31
+ return new Signal(value, options);
29
32
  }
30
33
  export {
31
34
  Signal,
package/package.json CHANGED
@@ -12,14 +12,14 @@
12
12
  "@rollup/plugin-node-resolve": "^16",
13
13
  "@rollup/plugin-typescript": "^12.1",
14
14
  "@types/node": "^22.15",
15
- "@vitest/coverage-istanbul": "^3.1",
15
+ "@vitest/coverage-istanbul": "^3.2",
16
16
  "dts-bundle-generator": "^9.5",
17
17
  "glob": "^11",
18
18
  "jsdom": "^26.1",
19
19
  "tslib": "^2.8",
20
20
  "typescript": "^5.8",
21
21
  "vite": "^6.3",
22
- "vitest": "^3.1"
22
+ "vitest": "^3.2"
23
23
  },
24
24
  "exports": {
25
25
  ".": {
@@ -54,5 +54,5 @@
54
54
  },
55
55
  "type": "module",
56
56
  "types": "./types/index.d.ts",
57
- "version": "0.15.0"
57
+ "version": "0.17.0"
58
58
  }
package/src/batch.ts CHANGED
@@ -2,7 +2,7 @@ import {type Effect, runEffect} from './effect';
2
2
  import {isEffect} from './helpers/is';
3
3
  import type {Subscription} from './subscription';
4
4
 
5
- export function flushEffects(): void {
5
+ export function flushHandlers(): void {
6
6
  while (batchDepth === 0 && batchedHandlers.size > 0) {
7
7
  const handlers = [...batchedHandlers];
8
8
 
@@ -33,7 +33,7 @@ export function stopBatch(): void {
33
33
  batchDepth -= 1;
34
34
  }
35
35
 
36
- flushEffects();
36
+ flushHandlers();
37
37
  }
38
38
 
39
39
  export const batchedHandlers = new Set<Effect | Subscription<unknown>>();
package/src/helpers/is.ts CHANGED
@@ -3,7 +3,7 @@ import type {Effect} from '../effect';
3
3
  import type {ReactiveArray} from '../value/array';
4
4
  import type {Computed} from '../value/computed';
5
5
  import type {Reactive} from '../value/reactive';
6
- import {signal, type Signal} from '../value/signal';
6
+ import type {Signal} from '../value/signal';
7
7
 
8
8
  /**
9
9
  * Is the value a reactive array?
@@ -1,9 +1,72 @@
1
+ import {batchDepth, batchedHandlers, flushHandlers} from '../batch';
1
2
  import {activeEffect} from '../effect';
2
- import {activeComputed} from '../value/computed';
3
+ import {type InternalComputed, activeComputed} from '../value/computed';
3
4
  import type {ReactiveState} from '../value/reactive';
4
- import {emitValue} from './emit';
5
5
 
6
- export function getValue<Value>(state: ReactiveState<Value>): Value {
6
+ export function differentArrays<Value>(
7
+ state: ReactiveState<Value[], Value>,
8
+ first: Value[],
9
+ second: Value[],
10
+ ): boolean {
11
+ let {length} = first;
12
+
13
+ if (length !== second.length) {
14
+ return true;
15
+ }
16
+
17
+ let offset = 0;
18
+
19
+ if (length >= 100) {
20
+ offset = Math.round(length / 10);
21
+ offset = offset > 25 ? 25 : offset;
22
+
23
+ for (let index = 0; index < offset; index += 1) {
24
+ if (!state.equal(first[index], second[index])) {
25
+ return true;
26
+ }
27
+ }
28
+ }
29
+
30
+ length -= offset;
31
+
32
+ for (let index = offset; index < length; index += 1) {
33
+ if (!state.equal(first[index], second[index])) {
34
+ return true;
35
+ }
36
+ }
37
+
38
+ return false;
39
+ }
40
+
41
+ export function differentValues<Value>(
42
+ state: ReactiveState<Value, Value>,
43
+ first: Value,
44
+ second: Value,
45
+ ): boolean {
46
+ return Array.isArray(first) && Array.isArray(second)
47
+ ? differentArrays(state as never, first, second)
48
+ : !state.equal(first, second);
49
+ }
50
+
51
+ export function emitValue<Value>(state: ReactiveState<Value, never>): void {
52
+ for (const computed of state.computeds) {
53
+ (computed as unknown as InternalComputed).effect.dirty = true;
54
+ }
55
+
56
+ for (const effect of state.effects) {
57
+ batchedHandlers.add(effect);
58
+ }
59
+
60
+ for (const [, subscription] of state.subscriptions) {
61
+ batchedHandlers.add(subscription as never);
62
+ }
63
+
64
+ if (batchDepth === 0) {
65
+ flushHandlers();
66
+ }
67
+ }
68
+
69
+ export function getValue<Value>(state: ReactiveState<Value, never>): Value {
7
70
  if (activeComputed != null) {
8
71
  state.computeds.add(activeComputed);
9
72
  }
@@ -14,14 +77,3 @@ export function getValue<Value>(state: ReactiveState<Value>): Value {
14
77
 
15
78
  return state.value;
16
79
  }
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
- }
@@ -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);
@@ -1,11 +1,10 @@
1
- import {emitArrayChanges, emitValue} from '../helpers/emit';
2
1
  import {arrayName} from '../helpers/is';
3
- import {getValue} from '../helpers/value';
2
+ import {differentArrays, emitValue, getValue} from '../helpers/value';
4
3
  import {type Computed, computed} from './computed';
5
- import {Reactive, type ReactiveState} from './reactive';
4
+ import {Reactive, type ReactiveOptions, type ReactiveState} from './reactive';
6
5
  import {type Signal, signal} from './signal';
7
6
 
8
- export class ReactiveArray<Item> extends Reactive<Item[]> {
7
+ export class ReactiveArray<Item> extends Reactive<Item[], Item> {
9
8
  #size = signal(0);
10
9
 
11
10
  /**
@@ -28,7 +27,7 @@ export class ReactiveArray<Item> extends Reactive<Item[]> {
28
27
  }
29
28
  }
30
29
 
31
- constructor(value: Item[]) {
30
+ constructor(value: Item[], options?: ReactiveOptions<Item>) {
32
31
  super(
33
32
  arrayName,
34
33
  new Proxy(value, {
@@ -39,6 +38,7 @@ export class ReactiveArray<Item> extends Reactive<Item[]> {
39
38
  set: (target, property, value) =>
40
39
  setValue(target, property, value, this.state, this.#size),
41
40
  }),
41
+ options,
42
42
  );
43
43
 
44
44
  this.#size.set(value.length);
@@ -51,6 +51,13 @@ export class ReactiveArray<Item> extends Reactive<Item[]> {
51
51
  return this.get().at(index);
52
52
  }
53
53
 
54
+ /**
55
+ * Clear the array
56
+ */
57
+ clear(): void {
58
+ this.length = 0;
59
+ }
60
+
54
61
  /**
55
62
  * @inheritdoc
56
63
  */
@@ -158,15 +165,18 @@ export class ReactiveArray<Item> extends Reactive<Item[]> {
158
165
  /**
159
166
  * Create a reactive array
160
167
  */
161
- export function array<Item>(value: Item[]): ReactiveArray<Item> {
162
- return new ReactiveArray(Array.isArray(value) ? value : []);
168
+ export function array<Item>(
169
+ value: Item[],
170
+ options?: ReactiveOptions<Item>,
171
+ ): ReactiveArray<Item> {
172
+ return new ReactiveArray(Array.isArray(value) ? value : [], options);
163
173
  }
164
174
 
165
175
  function setValue<Item>(
166
176
  target: Item[],
167
177
  property: PropertyKey,
168
- value: unknown,
169
- state: ReactiveState<Item[]>,
178
+ value: Item,
179
+ state: ReactiveState<Item[], Item>,
170
180
  length: Signal<number>,
171
181
  ): boolean {
172
182
  const isIndex = !Number.isNaN(Number(property));
@@ -178,7 +188,7 @@ function setValue<Item>(
178
188
 
179
189
  const previous = Reflect.get(target, property);
180
190
 
181
- if (!Object.is(previous, value)) {
191
+ if (!state.equal(previous, value)) {
182
192
  Reflect.set(target, property, value);
183
193
 
184
194
  emitValue(state);
@@ -192,7 +202,7 @@ function setValue<Item>(
192
202
  function updateArray<Item>(
193
203
  type: string,
194
204
  array: Item[],
195
- state: ReactiveState<Item[]>,
205
+ state: ReactiveState<Item[], Item>,
196
206
  length: Signal<number>,
197
207
  ): unknown {
198
208
  const affectsLength = lengthAffectingMethods.has(type);
@@ -207,7 +217,7 @@ function updateArray<Item>(
207
217
  if (
208
218
  affectsLength
209
219
  ? array.length !== previousLength
210
- : emitArrayChanges(previousArray, array)
220
+ : differentArrays(state, previousArray, array)
211
221
  ) {
212
222
  emitValue(state);
213
223
 
@@ -1,16 +1,16 @@
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
- type ComputedEffect = {
6
+ export type ComputedEffect = {
7
7
  dirty: boolean;
8
8
  instance: Effect;
9
9
  };
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 (!Object.is(this.state.value, value)) {
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) {
@@ -59,7 +59,7 @@ export class Computed<Value> extends Reactive<Value> {
59
59
  * @inheritdoc
60
60
  */
61
61
  get(): Value {
62
- if (activeComputed != null && activeComputed !== this) {
62
+ if (activeComputed != null && this !== activeComputed) {
63
63
  this.state.computeds.add(activeComputed);
64
64
  }
65
65
 
@@ -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>(callback: () => Value): Computed<Value> {
82
- return new Computed(callback);
81
+ export function computed<Value>(
82
+ callback: () => Value,
83
+ options?: ReactiveOptions<Value>,
84
+ ): Computed<Value> {
85
+ return new Computed(callback, options);
83
86
  }
@@ -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 ReactiveState<Value> = {
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
  };
@@ -1,10 +1,10 @@
1
1
  import {signalName} from '../helpers/is';
2
- import {getValue, setValue} from '../helpers/value';
3
- import {Reactive} from './reactive';
2
+ import {differentValues, 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,11 @@ export class Signal<Value> extends Reactive<Value> {
18
18
  * Set the value
19
19
  */
20
20
  set(value: Value): void {
21
- setValue(this.state, value);
21
+ if (differentValues(this.state, this.state.value, value)) {
22
+ this.state.value = value;
23
+
24
+ emitValue(this.state);
25
+ }
22
26
  }
23
27
 
24
28
  /**
@@ -32,6 +36,9 @@ export class Signal<Value> extends Reactive<Value> {
32
36
  /**
33
37
  * Create a reactive value
34
38
  */
35
- export function signal<Value>(value: Value): Signal<Value> {
36
- return new Signal(value);
39
+ export function signal<Value>(
40
+ value: Value,
41
+ options?: ReactiveOptions<Value>,
42
+ ): Signal<Value> {
43
+ return new Signal<Value>(value, options);
37
44
  }
package/types/batch.d.cts CHANGED
@@ -8,15 +8,15 @@ declare class Effect {
8
8
  }
9
9
  declare class Computed<Value> extends Reactive<Value> {
10
10
  private readonly effect;
11
- constructor(callback: () => Value);
11
+ constructor(callback: () => Value, options?: ReactiveOptions<Value>);
12
12
  /**
13
13
  * @inheritdoc
14
14
  */
15
15
  get(): Value;
16
16
  }
17
- declare abstract class Reactive<Value> {
18
- protected readonly state: ReactiveState<Value>;
19
- constructor(name: string, value: Value);
17
+ declare abstract class Reactive<Value, Equal = Value> {
18
+ protected readonly state: ReactiveState<Value, Equal>;
19
+ constructor(name: string, value: Value, options?: ReactiveOptions<Equal>);
20
20
  /**
21
21
  * Get the value
22
22
  */
@@ -42,22 +42,29 @@ declare abstract class Reactive<Value> {
42
42
  */
43
43
  unsubscribe(callback: (value: Value) => void): void;
44
44
  }
45
- export type ReactiveState<Value> = {
45
+ export type ReactiveOptions<Value> = {
46
+ /**
47
+ * Method to compare values for equality
48
+ */
49
+ equal?: (first: Value, second: Value) => boolean;
50
+ };
51
+ export type ReactiveState<Value, Equal> = {
46
52
  computeds: Set<Computed<unknown>>;
47
53
  effects: Set<Effect>;
54
+ equal: (first: Equal, second: Equal) => boolean;
48
55
  subscriptions: Map<(value: Value) => void, Subscription<Value>>;
49
56
  value: Value;
50
57
  };
51
58
  declare class Subscription<Value> {
52
- state: ReactiveState<Value>;
59
+ state: ReactiveState<Value, never>;
53
60
  callback: GenericCallback;
54
- constructor(state: ReactiveState<Value>, callback: GenericCallback);
61
+ constructor(state: ReactiveState<Value, never>, callback: GenericCallback);
55
62
  }
56
63
  /**
57
64
  * Unsubscribe from changes
58
65
  */
59
66
  export type Unsubscribe = () => void;
60
- export declare function flushEffects(): void;
67
+ export declare function flushHandlers(): void;
61
68
  /**
62
69
  * Start batching effects _(use `stopBatch` to flush and run batched effects)_
63
70
  */
package/types/batch.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type Effect } from './effect';
2
2
  import type { Subscription } from './subscription';
3
- export declare function flushEffects(): void;
3
+ export declare function flushHandlers(): void;
4
4
  /**
5
5
  * Start batching effects _(use `stopBatch` to flush and run batched effects)_
6
6
  */
@@ -8,15 +8,15 @@ declare class Effect {
8
8
  }
9
9
  declare class Computed<Value> extends Reactive<Value> {
10
10
  private readonly effect;
11
- constructor(callback: () => Value);
11
+ constructor(callback: () => Value, options?: ReactiveOptions<Value>);
12
12
  /**
13
13
  * @inheritdoc
14
14
  */
15
15
  get(): Value;
16
16
  }
17
- declare abstract class Reactive<Value> {
18
- protected readonly state: ReactiveState<Value>;
19
- constructor(name: string, value: Value);
17
+ declare abstract class Reactive<Value, Equal = Value> {
18
+ protected readonly state: ReactiveState<Value, Equal>;
19
+ constructor(name: string, value: Value, options?: ReactiveOptions<Equal>);
20
20
  /**
21
21
  * Get the value
22
22
  */
@@ -42,22 +42,29 @@ declare abstract class Reactive<Value> {
42
42
  */
43
43
  unsubscribe(callback: (value: Value) => void): void;
44
44
  }
45
- export type ReactiveState<Value> = {
45
+ export type ReactiveOptions<Value> = {
46
+ /**
47
+ * Method to compare values for equality
48
+ */
49
+ equal?: (first: Value, second: Value) => boolean;
50
+ };
51
+ export type ReactiveState<Value, Equal> = {
46
52
  computeds: Set<Computed<unknown>>;
47
53
  effects: Set<Effect>;
54
+ equal: (first: Equal, second: Equal) => boolean;
48
55
  subscriptions: Map<(value: Value) => void, Subscription<Value>>;
49
56
  value: Value;
50
57
  };
51
58
  declare class Subscription<Value> {
52
- state: ReactiveState<Value>;
59
+ state: ReactiveState<Value, never>;
53
60
  callback: GenericCallback;
54
- constructor(state: ReactiveState<Value>, callback: GenericCallback);
61
+ constructor(state: ReactiveState<Value, never>, callback: GenericCallback);
55
62
  }
56
63
  /**
57
64
  * Unsubscribe from changes
58
65
  */
59
66
  export type Unsubscribe = () => void;
60
- declare class ReactiveArray<Item> extends Reactive<Item[]> {
67
+ declare class ReactiveArray<Item> extends Reactive<Item[], Item> {
61
68
  #private;
62
69
  /**
63
70
  * The length of the array
@@ -67,11 +74,15 @@ declare class ReactiveArray<Item> extends Reactive<Item[]> {
67
74
  * Set the length of the array
68
75
  */
69
76
  set length(value: number);
70
- constructor(value: Item[]);
77
+ constructor(value: Item[], options?: ReactiveOptions<Item>);
71
78
  /**
72
79
  * Get an indexed item
73
80
  */
74
81
  at(index: number): Item | undefined;
82
+ /**
83
+ * Clear the array
84
+ */
85
+ clear(): void;
75
86
  /**
76
87
  * @inheritdoc
77
88
  */
@@ -126,7 +137,7 @@ declare class ReactiveArray<Item> extends Reactive<Item[]> {
126
137
  unshift(...items: Item[]): number;
127
138
  }
128
139
  declare class Signal<Value> extends Reactive<Value> {
129
- constructor(value: Value);
140
+ constructor(value: Value, options?: ReactiveOptions<Value>);
130
141
  /**
131
142
  * @inheritdoc
132
143
  */
@@ -2,7 +2,7 @@ import type { Effect } from '../effect';
2
2
  import type { ReactiveArray } from '../value/array';
3
3
  import type { Computed } from '../value/computed';
4
4
  import type { Reactive } from '../value/reactive';
5
- import { type Signal } from '../value/signal';
5
+ import type { Signal } from '../value/signal';
6
6
  /**
7
7
  * Is the value a reactive array?
8
8
  */