@oscarpalmer/mora 0.22.0 → 0.23.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 (43) hide show
  1. package/dist/batch.js +8 -9
  2. package/dist/constants.js +34 -0
  3. package/dist/effect.js +7 -8
  4. package/dist/helpers/is.js +8 -18
  5. package/dist/helpers/proxy.js +3 -2
  6. package/dist/helpers/value.js +7 -8
  7. package/dist/index.js +1 -1
  8. package/dist/models.js +0 -0
  9. package/dist/mora.full.js +218 -130
  10. package/dist/subscription.js +7 -5
  11. package/dist/value/array.js +24 -24
  12. package/dist/value/computed.js +18 -21
  13. package/dist/value/signal.js +2 -2
  14. package/dist/value/store.js +8 -2
  15. package/package.json +9 -10
  16. package/src/batch.ts +11 -13
  17. package/src/constants.ts +49 -0
  18. package/src/effect.ts +11 -16
  19. package/src/helpers/is.ts +41 -19
  20. package/src/helpers/proxy.ts +34 -38
  21. package/src/helpers/value.ts +19 -14
  22. package/src/index.ts +1 -0
  23. package/src/models.ts +66 -0
  24. package/src/subscription.ts +14 -16
  25. package/src/value/array.ts +86 -44
  26. package/src/value/computed.ts +29 -39
  27. package/src/value/reactive.ts +9 -24
  28. package/src/value/signal.ts +9 -3
  29. package/src/value/store.ts +40 -9
  30. package/types/batch.d.ts +3 -5
  31. package/types/constants.d.ts +14 -0
  32. package/types/effect.d.ts +2 -1
  33. package/types/helpers/is.d.ts +23 -10
  34. package/types/helpers/proxy.d.ts +2 -3
  35. package/types/helpers/value.d.ts +1 -1
  36. package/types/index.d.ts +1 -0
  37. package/types/models.d.ts +56 -0
  38. package/types/subscription.d.ts +3 -6
  39. package/types/value/array.d.ts +48 -7
  40. package/types/value/computed.d.ts +2 -11
  41. package/types/value/reactive.d.ts +8 -17
  42. package/types/value/signal.d.ts +7 -1
  43. package/types/value/store.d.ts +28 -4
@@ -1,5 +1,5 @@
1
1
  import { noop, subscribe } from "../subscription.js";
2
- import { arrayName } from "../helpers/is.js";
2
+ import { METHODS_AFFECTING_LENGTH, METHODS_UPDATE, NAME_ARRAY } from "../constants.js";
3
3
  import { Reactive } from "./reactive.js";
4
4
  import { computed } from "./computed.js";
5
5
  import { emitValue, equalArrays, getValue } from "../helpers/value.js";
@@ -15,28 +15,38 @@ var ReactiveArray = class extends Reactive {
15
15
  if (typeof value === "number" && value >= 0 && value !== this.state.value.length) this.get().length = value;
16
16
  }
17
17
  constructor(value, options) {
18
- super(arrayName, new Proxy(value, {
19
- get: (target, property) => updateMethods.has(property) ? updateArray(property, target, this.state, this.#size) : Reflect.get(target, property),
20
- set: (target, property, value$1) => setValueInProxy(target, property, value$1, this.state, true, this.#size)
18
+ super(NAME_ARRAY, new Proxy(value, {
19
+ get: (target, property) => METHODS_UPDATE.has(property) ? updateArray(property, target, this.state, this.#size) : Reflect.get(target, property),
20
+ set: (target, property, value$1) => setValueInProxy({
21
+ property,
22
+ target,
23
+ value: value$1,
24
+ isArray: true,
25
+ state: this.state,
26
+ length: this.#size
27
+ })
21
28
  }), options);
22
29
  this.#size.set(value.length);
23
30
  }
24
31
  clear() {
25
32
  this.length = 0;
26
33
  }
34
+ filter(callback) {
35
+ return computed(() => this.get().filter(callback));
36
+ }
27
37
  get(first) {
28
38
  if (typeof first === "number") return getReactiveValueInProxy(this, this.#indiced, first, true).get();
29
39
  if (first === "length") return this.length;
30
40
  return getValue(this.state);
31
41
  }
32
- filter(callback) {
33
- return computed(() => this.get().filter(callback));
34
- }
35
42
  map(callback) {
36
43
  return computed(() => this.get().map(callback));
37
44
  }
45
+ notify() {
46
+ emitValue(this.state);
47
+ }
38
48
  peek(value) {
39
- if (value === true) return this.#size.peek();
49
+ if (value === "length") return this.#size.peek();
40
50
  if (typeof value === "number") return this.state.value.at(value);
41
51
  return [...this.state.value];
42
52
  }
@@ -49,7 +59,7 @@ var ReactiveArray = class extends Reactive {
49
59
  set(first, second) {
50
60
  if (first == null || Array.isArray(first)) this.state.value.splice(0, this.state.value.length, ...first ?? []);
51
61
  else if (first === "length") this.length = second;
52
- else if (typeof first === "number") this.state.value[first] = second;
62
+ else if (typeof first === "number" && !Number.isNaN(first)) setAtIndex(this.state.value, first, second);
53
63
  }
54
64
  shift() {
55
65
  return this.state.value.shift();
@@ -73,7 +83,7 @@ function array(value, options) {
73
83
  return new ReactiveArray(Array.isArray(value) ? value : [], options);
74
84
  }
75
85
  function updateArray(type, array$1, state, length) {
76
- const affectsLength = lengthAffectingMethods.has(type);
86
+ const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
77
87
  const previousArray = affectsLength ? [] : [...array$1];
78
88
  const previousLength = array$1.length;
79
89
  return (...args) => {
@@ -85,18 +95,8 @@ function updateArray(type, array$1, state, length) {
85
95
  return result;
86
96
  };
87
97
  }
88
- var lengthAffectingMethods = new Set([
89
- "pop",
90
- "push",
91
- "shift",
92
- "unshift"
93
- ]);
94
- var updateMethods = new Set([
95
- ...lengthAffectingMethods,
96
- "copyWithin",
97
- "fill",
98
- "reverse",
99
- "sort",
100
- "splice"
101
- ]);
98
+ function setAtIndex(array$1, index, value) {
99
+ const actual = index < 0 ? array$1.length + index : index;
100
+ if (actual > -1) array$1[actual] = value;
101
+ }
102
102
  export { ReactiveArray, array };
@@ -1,39 +1,36 @@
1
- import { computedName } from "../helpers/is.js";
2
- import { activeEffect, effect, runEffect } from "../effect.js";
3
- import { batchDepth, batchedHandlers } from "../batch.js";
1
+ import { ACTIVE, BATCH, NAME_COMPUTED } from "../constants.js";
2
+ import { effect, runEffect } from "../effect.js";
4
3
  import { Reactive } from "./reactive.js";
5
- let activeComputed;
6
4
  var Computed = class extends Reactive {
7
5
  effect = {
8
6
  dirty: true,
9
7
  instance: void 0
10
8
  };
11
9
  constructor(callback, options) {
12
- super(computedName, void 0, options);
10
+ super(NAME_COMPUTED, void 0, options);
13
11
  this.effect.instance = effect(() => {
14
- if (this.effect.dirty) {
15
- const previousComputed = activeComputed;
16
- activeComputed = this;
17
- const value = callback();
18
- activeComputed = previousComputed;
19
- if (!this.state.equal(this.state.value, value)) {
20
- this.state.value = value;
21
- for (const computed$1 of this.state.computeds) computed$1.effect.dirty = true;
22
- for (const effect$1 of this.state.effects) batchedHandlers.add(effect$1);
23
- for (const [, subscription] of this.state.subscriptions) subscription.callback(value);
24
- }
25
- this.effect.dirty = false;
12
+ if (!this.effect.dirty) return;
13
+ const previousComputed = ACTIVE.computed;
14
+ ACTIVE.computed = this;
15
+ const value = callback();
16
+ ACTIVE.computed = previousComputed;
17
+ if (!this.state.equal(this.state.value, value)) {
18
+ this.state.value = value;
19
+ for (const computed$1 of this.state.computeds) computed$1.effect.dirty = true;
20
+ for (const effect$1 of this.state.effects) BATCH.handlers.add(effect$1);
21
+ for (const [, subscription] of this.state.subscriptions) subscription.callback(value);
26
22
  }
23
+ this.effect.dirty = false;
27
24
  });
28
25
  }
29
26
  get() {
30
- if (activeComputed != null && this !== activeComputed) this.state.computeds.add(activeComputed);
31
- if (activeEffect != null && activeEffect !== this.effect.instance) this.state.effects.add(activeEffect);
32
- if (this.effect.dirty && batchDepth === 0) runEffect(this.effect.instance);
27
+ if (ACTIVE.computed != null && this !== ACTIVE.computed) this.state.computeds.add(ACTIVE.computed);
28
+ if (ACTIVE.effect != null && ACTIVE.effect !== this.effect.instance) this.state.effects.add(ACTIVE.effect);
29
+ if (this.effect.dirty && BATCH.depth === 0) runEffect(this.effect.instance);
33
30
  return this.state.value;
34
31
  }
35
32
  };
36
33
  function computed(callback, options) {
37
34
  return new Computed(callback, options);
38
35
  }
39
- export { Computed, activeComputed, computed };
36
+ export { Computed, computed };
@@ -1,9 +1,9 @@
1
- import { signalName } from "../helpers/is.js";
1
+ import { NAME_SIGNAL } from "../constants.js";
2
2
  import { Reactive } from "./reactive.js";
3
3
  import { emitValue, getValue } from "../helpers/value.js";
4
4
  var Signal = class extends Reactive {
5
5
  constructor(value, options) {
6
- super(signalName, value, options);
6
+ super(NAME_SIGNAL, value, options);
7
7
  }
8
8
  get() {
9
9
  return getValue(this.state);
@@ -1,5 +1,5 @@
1
1
  import { noop, subscribe } from "../subscription.js";
2
- import { storeName } from "../helpers/is.js";
2
+ import { NAME_STORE } from "../constants.js";
3
3
  import { Reactive } from "./reactive.js";
4
4
  import { getValue } from "../helpers/value.js";
5
5
  import { getReactiveValueInProxy, setProxyValue, setValueInProxy } from "../helpers/proxy.js";
@@ -7,7 +7,13 @@ import { isKey, isPlainObject } from "@oscarpalmer/atoms/is";
7
7
  var Store = class extends Reactive {
8
8
  #keyed = /* @__PURE__ */ new Map();
9
9
  constructor(value, options) {
10
- super(storeName, new Proxy(value, { set: (target, property, value$1) => setValueInProxy(target, property, value$1, this.state, false) }), options);
10
+ super(NAME_STORE, new Proxy(value, { set: (target, property, value$1) => setValueInProxy({
11
+ target,
12
+ property,
13
+ value: value$1,
14
+ isArray: false,
15
+ state: this.state
16
+ }) }), options);
11
17
  }
12
18
  get(key) {
13
19
  return isKey(key) ? getReactiveValueInProxy(this, this.#keyed, key, false).get() : getValue(this.state);
package/package.json CHANGED
@@ -4,23 +4,22 @@
4
4
  "url": "https://oscarpalmer.se"
5
5
  },
6
6
  "dependencies": {
7
- "@oscarpalmer/atoms": "^0.102"
7
+ "@oscarpalmer/atoms": "^0.114"
8
8
  },
9
9
  "description": "Signals and stuff…",
10
10
  "devDependencies": {
11
- "@biomejs/biome": "^2.2",
11
+ "@biomejs/biome": "^2.3",
12
12
  "@rollup/plugin-node-resolve": "^16",
13
- "@rollup/plugin-typescript": "^12.1",
14
- "@types/node": "^24.3",
15
- "@vitest/coverage-istanbul": "^3.2",
16
- "dts-bundle-generator": "^9.5",
13
+ "@rollup/plugin-typescript": "^12.3",
14
+ "@types/node": "^24.9",
15
+ "@vitest/coverage-istanbul": "^4",
17
16
  "glob": "^11",
18
- "jsdom": "^26.1",
19
- "rollup": "^4.50",
17
+ "jsdom": "^27.1",
18
+ "rollup": "^4.52",
20
19
  "tslib": "^2.8",
21
20
  "typescript": "^5.9",
22
21
  "vite": "npm:rolldown-vite@latest",
23
- "vitest": "^3.2"
22
+ "vitest": "^4"
24
23
  },
25
24
  "exports": {
26
25
  "./package.json": "./package.json",
@@ -48,5 +47,5 @@
48
47
  },
49
48
  "type": "module",
50
49
  "types": "./types/index.d.ts",
51
- "version": "0.22.0"
50
+ "version": "0.23.0"
52
51
  }
package/src/batch.ts CHANGED
@@ -1,12 +1,12 @@
1
- import {type Effect, runEffect} from './effect';
1
+ import {BATCH} from './constants';
2
+ import {runEffect} from './effect';
2
3
  import {isEffect} from './helpers/is';
3
- import type {Subscription} from './subscription';
4
4
 
5
5
  export function flushHandlers(): void {
6
- while (batchDepth === 0 && batchedHandlers.size > 0) {
7
- const handlers = [...batchedHandlers];
6
+ while (BATCH.depth === 0 && BATCH.handlers.size > 0) {
7
+ const handlers = [...BATCH.handlers];
8
8
 
9
- batchedHandlers.clear();
9
+ BATCH.handlers.clear();
10
10
 
11
11
  for (const handler of handlers) {
12
12
  if (isEffect(handler)) {
@@ -19,23 +19,21 @@ export function flushHandlers(): void {
19
19
  }
20
20
 
21
21
  /**
22
- * Start batching effects _(use `stopBatch` to flush and run batched effects)_
22
+ * Start batching effects
23
+ *
24
+ * _(Use {@link stopBatch} to flush and run batched effects)_
23
25
  */
24
26
  export function startBatch(): void {
25
- batchDepth += 1;
27
+ BATCH.depth += 1;
26
28
  }
27
29
 
28
30
  /**
29
31
  * Stop batching effects and flush _(run)_ them
30
32
  */
31
33
  export function stopBatch(): void {
32
- if (batchDepth > 0) {
33
- batchDepth -= 1;
34
+ if (BATCH.depth > 0) {
35
+ BATCH.depth -= 1;
34
36
  }
35
37
 
36
38
  flushHandlers();
37
39
  }
38
-
39
- export const batchedHandlers = new Set<Effect | Subscription>();
40
-
41
- export let batchDepth = 0;
@@ -0,0 +1,49 @@
1
+ import type {Effect} from './effect';
2
+ import type {Active, Batch} from './models';
3
+ import type {Subscription} from './subscription';
4
+
5
+ export const ACTIVE: Active = {};
6
+
7
+ export const ARRAY_THRESHOLD = 100;
8
+
9
+ export const ARRAY_OFFSET = 25;
10
+
11
+ export const ARRAY_PEEK = 10;
12
+
13
+ export const BATCH: Batch = {
14
+ depth: 0,
15
+ handlers: new Set<Effect | Subscription>(),
16
+ };
17
+
18
+ export const METHODS_AFFECTING_LENGTH: Set<string> = new Set<string>([
19
+ 'pop',
20
+ 'push',
21
+ 'shift',
22
+ 'unshift',
23
+ ]);
24
+
25
+ export const METHODS_UPDATE: Set<string> = new Set<string>([
26
+ ...METHODS_AFFECTING_LENGTH,
27
+ 'copyWithin',
28
+ 'fill',
29
+ 'reverse',
30
+ 'sort',
31
+ 'splice',
32
+ ]);
33
+
34
+ export const NAME_ARRAY = 'array';
35
+
36
+ export const NAME_COMPUTED = 'computed';
37
+
38
+ export const NAME_EFFECT = 'effect';
39
+
40
+ export const NAME_SIGNAL = 'signal';
41
+
42
+ export const NAME_STORE = 'store';
43
+
44
+ export const NAMES: Set<string> = new Set([
45
+ NAME_ARRAY,
46
+ NAME_COMPUTED,
47
+ NAME_SIGNAL,
48
+ NAME_STORE,
49
+ ]);
package/src/effect.ts CHANGED
@@ -1,13 +1,6 @@
1
1
  import type {GenericCallback} from '@oscarpalmer/atoms/models';
2
- import {effectName} from './helpers/is';
3
-
4
- type EffectState = {
5
- callback: GenericCallback;
6
- };
7
-
8
- type InternalEffect = {
9
- state: EffectState;
10
- };
2
+ import {ACTIVE, NAME_EFFECT} from './constants';
3
+ import type {EffectState, InternalEffect} from './models';
11
4
 
12
5
  export class Effect {
13
6
  private declare readonly $mora: string;
@@ -16,7 +9,7 @@ export class Effect {
16
9
 
17
10
  constructor(callback: GenericCallback) {
18
11
  Object.defineProperty(this, '$mora', {
19
- value: effectName,
12
+ value: NAME_EFFECT,
20
13
  });
21
14
 
22
15
  this.state = {
@@ -28,22 +21,24 @@ export class Effect {
28
21
  }
29
22
 
30
23
  export function runEffect(effect: Effect): void {
31
- const previousEffect = activeEffect;
24
+ const previousEffect = ACTIVE.effect;
32
25
 
33
- activeEffect = effect;
26
+ ACTIVE.effect = effect;
34
27
 
35
28
  try {
36
29
  (effect as unknown as InternalEffect).state.callback();
37
30
  } finally {
38
- activeEffect = previousEffect;
31
+ ACTIVE.effect = previousEffect;
39
32
  }
40
33
  }
41
34
 
42
35
  /**
43
36
  * Create an effect
37
+ * @param callback Callback for handling signal effects
38
+ * @returns Effect
44
39
  */
45
40
  export function effect(callback: GenericCallback): Effect {
46
- return new Effect(callback);
41
+ return typeof callback === 'function'
42
+ ? new Effect(callback)
43
+ : (undefined as never);
47
44
  }
48
-
49
- export let activeEffect: Effect | undefined;
package/src/helpers/is.ts CHANGED
@@ -1,4 +1,12 @@
1
1
  import type {PlainObject} from '@oscarpalmer/atoms/models';
2
+ import {
3
+ NAME_ARRAY,
4
+ NAME_COMPUTED,
5
+ NAME_EFFECT,
6
+ NAME_SIGNAL,
7
+ NAME_STORE,
8
+ NAMES,
9
+ } from '../constants';
2
10
  import type {Effect} from '../effect';
3
11
  import type {ReactiveArray} from '../value/array';
4
12
  import type {Computed} from '../value/computed';
@@ -8,23 +16,29 @@ import type {Store} from '../value/store';
8
16
 
9
17
  /**
10
18
  * Is the value a reactive array?
19
+ * @param value Value to check
20
+ * @returns True if value is a {@link ReactiveArray}
11
21
  */
12
- export function isArray(value: unknown): value is ReactiveArray<unknown> {
13
- return isMora<ReactiveArray<unknown>>(value, arrayName);
22
+ export function isArray<Item>(value: unknown): value is ReactiveArray<Item> {
23
+ return isMora<ReactiveArray<Item>>(value, NAME_ARRAY);
14
24
  }
15
25
 
16
26
  /**
17
27
  * Is the value a computed signal?
28
+ * @param value Value to check
29
+ * @returns True if value is a {@link Computed}
18
30
  */
19
- export function isComputed(value: unknown): value is Computed<unknown> {
20
- return isMora<Computed<unknown>>(value, computedName);
31
+ export function isComputed<Value>(value: unknown): value is Computed<Value> {
32
+ return isMora<Computed<Value>>(value, NAME_COMPUTED);
21
33
  }
22
34
 
23
35
  /**
24
36
  * Is the value an effect?
37
+ * @param value Value to check
38
+ * @returns True if value is an {@link Effect}
25
39
  */
26
40
  export function isEffect(value: unknown): value is Effect {
27
- return isMora<Effect>(value, effectName);
41
+ return isMora<Effect>(value, NAME_EFFECT);
28
42
  }
29
43
 
30
44
  function isMora<T>(value: unknown, name: string | Set<string>): value is T {
@@ -38,25 +52,33 @@ function isMora<T>(value: unknown, name: string | Set<string>): value is T {
38
52
  );
39
53
  }
40
54
 
41
- export function isReactive(value: unknown): value is Reactive<unknown> {
42
- return isMora<Reactive<unknown>>(value, reactiveNames);
55
+ /**
56
+ * Is the value reactive?
57
+ * @param value Value to check
58
+ * @returns True if value is a {@link Reactive}
59
+ */
60
+ export function isReactive<Value, Equal = Value>(
61
+ value: unknown,
62
+ ): value is Reactive<Value, Equal> {
63
+ return isMora<Reactive<Value, Equal>>(value, NAMES);
43
64
  }
44
65
 
45
66
  /**
46
67
  * Is the value a signal?
68
+ * @param value Value to check
69
+ * @returns True if value is a {@link Signal}
47
70
  */
48
- export function isSignal(value: unknown): value is Signal<unknown> {
49
- return isMora<Signal<unknown>>(value, signalName);
71
+ export function isSignal<Value>(value: unknown): value is Signal<Value> {
72
+ return isMora<Signal<Value>>(value, NAME_SIGNAL);
50
73
  }
51
74
 
52
- export function isStore(value: unknown): value is Store<PlainObject> {
53
- return isMora<Reactive<unknown>>(value, storeName);
75
+ /**
76
+ * Is the value a reactive store?
77
+ * @param value Value to check
78
+ * @returns True if value is a {@link Store}
79
+ */
80
+ export function isStore<Value extends PlainObject>(
81
+ value: unknown,
82
+ ): value is Store<Value> {
83
+ return isMora<Store<Value>>(value, NAME_STORE);
54
84
  }
55
-
56
- export const arrayName = 'array';
57
- export const computedName = 'computed';
58
- export const effectName = 'effect';
59
- export const signalName = 'signal';
60
- export const storeName = 'store';
61
-
62
- const reactiveNames = new Set([arrayName, computedName, signalName, storeName]);
@@ -4,50 +4,49 @@ import type {
4
4
  PlainObject,
5
5
  } from '@oscarpalmer/atoms/models';
6
6
  import {startBatch, stopBatch} from '../batch';
7
+ import type {SetValueInProxyParameters} from '../models';
7
8
  import type {ReactiveArray} from '../value/array';
8
9
  import {type Computed, computed} from '../value/computed';
9
- import type {ReactiveState} from '../value/reactive';
10
- import type {Signal} from '../value/signal';
11
10
  import type {Store} from '../value/store';
12
11
  import {emitValue} from './value';
13
12
 
14
13
  export function getReactiveValueInProxy<Value>(
15
- array: ReactiveArray<Value>,
16
- mapped: Map<Key, Computed<unknown>>,
17
- index: number,
18
- isArray: true,
19
- ): Computed<unknown>;
14
+ array: ReactiveArray<Value>,
15
+ mapped: Map<Key, Computed<unknown>>,
16
+ index: number,
17
+ isArray: true,
18
+ ): Computed<unknown>;
20
19
 
21
20
  export function getReactiveValueInProxy<Value extends PlainObject>(
22
- store: Store<Value>,
23
- mapped: Map<Key, Computed<unknown>>,
24
- key: Key,
25
- isArray: false,
26
- ): Computed<unknown>;
21
+ store: Store<Value>,
22
+ mapped: Map<Key, Computed<unknown>>,
23
+ key: Key,
24
+ isArray: false,
25
+ ): Computed<unknown>;
27
26
 
28
27
  export function getReactiveValueInProxy(
29
- reactive: ReactiveArray<unknown> | Store<PlainObject>,
30
- mapped: Map<Key, Computed<unknown>>,
31
- key: Key,
32
- isArray: boolean,
33
- ): Computed<unknown> {
34
- let item = mapped.get(key);
35
-
36
- if (item == null) {
37
- item = computed(() => {
38
- const value = reactive.get();
39
-
40
- return isArray
41
- ? (value as unknown[]).at(key as number)
42
- : (value as PlainObject)[key];
43
- }) as Computed<unknown>;
44
-
45
- mapped.set(key, item);
46
- }
28
+ reactive: ReactiveArray<unknown> | Store<PlainObject>,
29
+ mapped: Map<Key, Computed<unknown>>,
30
+ key: Key,
31
+ isArray: boolean,
32
+ ): Computed<unknown> {
33
+ let item = mapped.get(key);
34
+
35
+ if (item == null) {
36
+ item = computed(() => {
37
+ const value = reactive.get();
38
+
39
+ return isArray
40
+ ? (value as unknown[]).at(key as number)
41
+ : (value as PlainObject)[key];
42
+ }) as Computed<unknown>;
47
43
 
48
- return item;
44
+ mapped.set(key, item);
49
45
  }
50
46
 
47
+ return item;
48
+ }
49
+
51
50
  export function setProxyValue(
52
51
  proxy: ArrayOrPlainObject,
53
52
  value: ArrayOrPlainObject,
@@ -83,18 +82,15 @@ export function setProxyValue(
83
82
  }
84
83
 
85
84
  export function setValueInProxy<Value extends ArrayOrPlainObject, Equal>(
86
- target: Value,
87
- property: PropertyKey,
88
- value: unknown,
89
- state: ReactiveState<Value, Equal>,
90
- isArray: boolean,
91
- length?: Signal<number>,
85
+ parameters: SetValueInProxyParameters<Value, Equal>,
92
86
  ): boolean {
87
+ const {isArray, length, property, state, target, value} = parameters;
88
+
93
89
  if (isArray) {
94
90
  const isIndex = !Number.isNaN(Number(property));
95
91
  const isLength = property === 'length';
96
92
 
97
- if (!isIndex && !isLength) {
93
+ if (!(isIndex || isLength)) {
98
94
  return Reflect.set(target, property, value);
99
95
  }
100
96
  }
@@ -1,7 +1,12 @@
1
- import {batchDepth, batchedHandlers, flushHandlers} from '../batch';
2
- import {activeEffect} from '../effect';
3
- import {activeComputed, type InternalComputed} from '../value/computed';
4
- import type {ReactiveState} from '../value/reactive';
1
+ import {flushHandlers} from '../batch';
2
+ import {
3
+ ACTIVE,
4
+ ARRAY_OFFSET,
5
+ ARRAY_PEEK,
6
+ ARRAY_THRESHOLD,
7
+ BATCH,
8
+ } from '../constants';
9
+ import type {InternalComputed, ReactiveState} from '../models';
5
10
 
6
11
  export function emitValue<Value>(state: ReactiveState<Value, never>): void {
7
12
  for (const computed of state.computeds) {
@@ -9,14 +14,14 @@ export function emitValue<Value>(state: ReactiveState<Value, never>): void {
9
14
  }
10
15
 
11
16
  for (const effect of state.effects) {
12
- batchedHandlers.add(effect);
17
+ BATCH.handlers.add(effect);
13
18
  }
14
19
 
15
20
  for (const [, subscription] of state.subscriptions) {
16
- batchedHandlers.add(subscription as never);
21
+ BATCH.handlers.add(subscription);
17
22
  }
18
23
 
19
- if (batchDepth === 0) {
24
+ if (BATCH.depth === 0) {
20
25
  flushHandlers();
21
26
  }
22
27
  }
@@ -34,9 +39,9 @@ export function equalArrays<Value>(
34
39
 
35
40
  let offset = 0;
36
41
 
37
- if (length >= 100) {
38
- offset = Math.round(length / 10);
39
- offset = offset > 25 ? 25 : offset;
42
+ if (length >= ARRAY_THRESHOLD) {
43
+ offset = Math.round(length / ARRAY_PEEK);
44
+ offset = offset > ARRAY_OFFSET ? ARRAY_OFFSET : offset;
40
45
 
41
46
  for (let index = 0; index < offset; index += 1) {
42
47
  if (!state.equal(first[index], second[index])) {
@@ -57,12 +62,12 @@ export function equalArrays<Value>(
57
62
  }
58
63
 
59
64
  export function getValue<Value>(state: ReactiveState<Value, never>): Value {
60
- if (activeComputed != null) {
61
- state.computeds.add(activeComputed);
65
+ if (ACTIVE.computed != null) {
66
+ state.computeds.add(ACTIVE.computed);
62
67
  }
63
68
 
64
- if (activeEffect != null) {
65
- state.effects.add(activeEffect);
69
+ if (ACTIVE.effect != null) {
70
+ state.effects.add(ACTIVE.effect);
66
71
  }
67
72
 
68
73
  return state.value;
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@ export {
7
7
  isReactive,
8
8
  isSignal,
9
9
  } from './helpers/is';
10
+ export type {Unsubscribe} from './models';
10
11
  export {array, type ReactiveArray} from './value/array';
11
12
  export {computed, type Computed} from './value/computed';
12
13
  export type {Reactive} from './value/reactive';