@oscarpalmer/mora 0.26.0 → 0.28.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 (46) hide show
  1. package/dist/batch.d.mts +14 -0
  2. package/dist/{batch.js → batch.mjs} +13 -3
  3. package/dist/constants.d.mts +20 -0
  4. package/dist/{constants.js → constants.mjs} +2 -0
  5. package/dist/effect.d.mts +17 -0
  6. package/dist/{effect.js → effect.mjs} +11 -4
  7. package/dist/helpers/is.d.mts +47 -0
  8. package/dist/helpers/is.mjs +55 -0
  9. package/dist/helpers/proxy.d.mts +15 -0
  10. package/dist/helpers/proxy.mjs +72 -0
  11. package/dist/helpers/value.d.mts +8 -0
  12. package/dist/helpers/{value.js → value.mjs} +4 -2
  13. package/dist/index.d.mts +10 -0
  14. package/dist/index.mjs +8 -0
  15. package/dist/models.d.mts +62 -0
  16. package/dist/models.mjs +1 -0
  17. package/dist/{mora.full.js → mora.full.mjs} +206 -106
  18. package/dist/subscription.d.mts +15 -0
  19. package/dist/{subscription.js → subscription.mjs} +2 -0
  20. package/dist/value/array.d.mts +156 -0
  21. package/dist/value/array.mjs +165 -0
  22. package/dist/value/computed.d.mts +21 -0
  23. package/dist/value/computed.mjs +68 -0
  24. package/dist/value/reactive.d.mts +40 -0
  25. package/dist/value/{reactive.js → reactive.mjs} +25 -2
  26. package/dist/value/signal.d.mts +44 -0
  27. package/dist/value/signal.mjs +59 -0
  28. package/dist/value/store.d.mts +112 -0
  29. package/dist/value/store.mjs +81 -0
  30. package/package.json +41 -35
  31. package/src/constants.ts +1 -6
  32. package/src/helpers/is.ts +1 -1
  33. package/src/helpers/proxy.ts +64 -17
  34. package/src/models.ts +3 -1
  35. package/src/value/array.ts +79 -23
  36. package/src/value/computed.ts +65 -30
  37. package/src/value/signal.ts +77 -9
  38. package/src/value/store.ts +101 -12
  39. package/dist/helpers/is.js +0 -23
  40. package/dist/helpers/proxy.js +0 -48
  41. package/dist/index.js +0 -8
  42. package/dist/models.js +0 -0
  43. package/dist/value/array.js +0 -100
  44. package/dist/value/computed.js +0 -36
  45. package/dist/value/signal.js +0 -24
  46. package/dist/value/store.js +0 -43
@@ -0,0 +1,14 @@
1
+ //#region src/batch.d.ts
2
+ declare function flushHandlers(): void;
3
+ /**
4
+ * Start batching effects
5
+ *
6
+ * _(Use {@link stopBatch} to flush and run batched effects)_
7
+ */
8
+ declare function startBatch(): void;
9
+ /**
10
+ * Stop batching effects and flush _(run)_ them
11
+ */
12
+ declare function stopBatch(): void;
13
+ //#endregion
14
+ export { flushHandlers, startBatch, stopBatch };
@@ -1,6 +1,7 @@
1
- import { BATCH } from "./constants.js";
2
- import { runEffect } from "./effect.js";
3
- import { isEffect } from "./helpers/is.js";
1
+ import { BATCH } from "./constants.mjs";
2
+ import { runEffect } from "./effect.mjs";
3
+ import { isEffect } from "./helpers/is.mjs";
4
+ //#region src/batch.ts
4
5
  function flushHandlers() {
5
6
  while (BATCH.depth === 0 && BATCH.handlers.size > 0) {
6
7
  const handlers = [...BATCH.handlers];
@@ -9,11 +10,20 @@ function flushHandlers() {
9
10
  else handler.callback(handler.state.value);
10
11
  }
11
12
  }
13
+ /**
14
+ * Start batching effects
15
+ *
16
+ * _(Use {@link stopBatch} to flush and run batched effects)_
17
+ */
12
18
  function startBatch() {
13
19
  BATCH.depth += 1;
14
20
  }
21
+ /**
22
+ * Stop batching effects and flush _(run)_ them
23
+ */
15
24
  function stopBatch() {
16
25
  if (BATCH.depth > 0) BATCH.depth -= 1;
17
26
  flushHandlers();
18
27
  }
28
+ //#endregion
19
29
  export { flushHandlers, startBatch, stopBatch };
@@ -0,0 +1,20 @@
1
+ import { Active, Batch } from "./models.mjs";
2
+
3
+ //#region src/constants.d.ts
4
+ declare const ACTIVE: Active;
5
+ declare const ARRAY_THRESHOLD = 100;
6
+ declare const ARRAY_OFFSET = 25;
7
+ declare const ARRAY_PEEK = 10;
8
+ declare const BATCH: Batch;
9
+ declare const METHODS_AFFECTING_LENGTH: Set<string>;
10
+ declare const METHODS_UPDATE: Set<string>;
11
+ declare const NAME_ARRAY = "array";
12
+ declare const NAME_COMPUTED = "computed";
13
+ declare const NAME_EFFECT = "effect";
14
+ declare const NAME_MORA = "$mora";
15
+ declare const NAME_SIGNAL = "signal";
16
+ declare const NAME_STORE = "store";
17
+ declare const NAME_ALL: Set<string>;
18
+ declare const PROPERTY_LENGTH = "length";
19
+ //#endregion
20
+ export { ACTIVE, ARRAY_OFFSET, ARRAY_PEEK, ARRAY_THRESHOLD, BATCH, METHODS_AFFECTING_LENGTH, METHODS_UPDATE, NAME_ALL, NAME_ARRAY, NAME_COMPUTED, NAME_EFFECT, NAME_MORA, NAME_SIGNAL, NAME_STORE, PROPERTY_LENGTH };
@@ -1,3 +1,4 @@
1
+ //#region src/constants.ts
1
2
  const ACTIVE = {};
2
3
  const ARRAY_THRESHOLD = 100;
3
4
  const ARRAY_OFFSET = 25;
@@ -33,4 +34,5 @@ const NAME_ALL = new Set([
33
34
  NAME_STORE
34
35
  ]);
35
36
  const PROPERTY_LENGTH = "length";
37
+ //#endregion
36
38
  export { ACTIVE, ARRAY_OFFSET, ARRAY_PEEK, ARRAY_THRESHOLD, BATCH, METHODS_AFFECTING_LENGTH, METHODS_UPDATE, NAME_ALL, NAME_ARRAY, NAME_COMPUTED, NAME_EFFECT, NAME_MORA, NAME_SIGNAL, NAME_STORE, PROPERTY_LENGTH };
@@ -0,0 +1,17 @@
1
+ import { GenericCallback } from "@oscarpalmer/atoms/models";
2
+
3
+ //#region src/effect.d.ts
4
+ declare class Effect {
5
+ private readonly $mora;
6
+ private readonly state;
7
+ constructor(callback: GenericCallback);
8
+ }
9
+ declare function runEffect(effect: Effect): void;
10
+ /**
11
+ * Create an effect
12
+ * @param callback Callback for handling signal effects
13
+ * @returns Effect
14
+ */
15
+ declare function effect(callback: GenericCallback): Effect;
16
+ //#endregion
17
+ export { Effect, effect, runEffect };
@@ -1,4 +1,5 @@
1
- import { ACTIVE, NAME_EFFECT, NAME_MORA } from "./constants.js";
1
+ import { ACTIVE, NAME_EFFECT, NAME_MORA } from "./constants.mjs";
2
+ //#region src/effect.ts
2
3
  var Effect = class {
3
4
  constructor(callback) {
4
5
  Object.defineProperty(this, NAME_MORA, { value: NAME_EFFECT });
@@ -6,16 +7,22 @@ var Effect = class {
6
7
  runEffect(this);
7
8
  }
8
9
  };
9
- function runEffect(effect$1) {
10
+ function runEffect(effect) {
10
11
  const previousEffect = ACTIVE.effect;
11
- ACTIVE.effect = effect$1;
12
+ ACTIVE.effect = effect;
12
13
  try {
13
- effect$1.state.callback();
14
+ effect.state.callback();
14
15
  } finally {
15
16
  ACTIVE.effect = previousEffect;
16
17
  }
17
18
  }
19
+ /**
20
+ * Create an effect
21
+ * @param callback Callback for handling signal effects
22
+ * @returns Effect
23
+ */
18
24
  function effect(callback) {
19
25
  return typeof callback === "function" ? new Effect(callback) : void 0;
20
26
  }
27
+ //#endregion
21
28
  export { Effect, effect, runEffect };
@@ -0,0 +1,47 @@
1
+ import { Effect } from "../effect.mjs";
2
+ import { Reactive } from "../value/reactive.mjs";
3
+ import { Computed } from "../value/computed.mjs";
4
+ import { Signal } from "../value/signal.mjs";
5
+ import { ReactiveArray } from "../value/array.mjs";
6
+ import { Store } from "../value/store.mjs";
7
+ import { PlainObject } from "@oscarpalmer/atoms/models";
8
+
9
+ //#region src/helpers/is.d.ts
10
+ /**
11
+ * Is the value a reactive array?
12
+ * @param value Value to check
13
+ * @returns True if value is a {@link ReactiveArray}
14
+ */
15
+ declare function isArray<Item>(value: unknown): value is ReactiveArray<Item>;
16
+ /**
17
+ * Is the value a computed signal?
18
+ * @param value Value to check
19
+ * @returns True if value is a {@link Computed}
20
+ */
21
+ declare function isComputed<Value>(value: unknown): value is Computed<Value>;
22
+ /**
23
+ * Is the value an effect?
24
+ * @param value Value to check
25
+ * @returns True if value is an {@link Effect}
26
+ */
27
+ declare function isEffect(value: unknown): value is Effect;
28
+ /**
29
+ * Is the value reactive?
30
+ * @param value Value to check
31
+ * @returns True if value is a {@link Reactive}
32
+ */
33
+ declare function isReactive<Value, Equal = Value>(value: unknown): value is Reactive<Value, Equal>;
34
+ /**
35
+ * Is the value a signal?
36
+ * @param value Value to check
37
+ * @returns True if value is a {@link Signal}
38
+ */
39
+ declare function isSignal<Value>(value: unknown): value is Signal<Value>;
40
+ /**
41
+ * Is the value a reactive store?
42
+ * @param value Value to check
43
+ * @returns True if value is a {@link Store}
44
+ */
45
+ declare function isStore<Value extends PlainObject>(value: unknown): value is Store<Value>;
46
+ //#endregion
47
+ export { isArray, isComputed, isEffect, isReactive, isSignal, isStore };
@@ -0,0 +1,55 @@
1
+ import { NAME_ALL, NAME_ARRAY, NAME_COMPUTED, NAME_EFFECT, NAME_SIGNAL, NAME_STORE } from "../constants.mjs";
2
+ //#region src/helpers/is.ts
3
+ /**
4
+ * Is the value a reactive array?
5
+ * @param value Value to check
6
+ * @returns True if value is a {@link ReactiveArray}
7
+ */
8
+ function isArray(value) {
9
+ return isMora(value, NAME_ARRAY);
10
+ }
11
+ /**
12
+ * Is the value a computed signal?
13
+ * @param value Value to check
14
+ * @returns True if value is a {@link Computed}
15
+ */
16
+ function isComputed(value) {
17
+ return isMora(value, NAME_COMPUTED);
18
+ }
19
+ /**
20
+ * Is the value an effect?
21
+ * @param value Value to check
22
+ * @returns True if value is an {@link Effect}
23
+ */
24
+ function isEffect(value) {
25
+ return isMora(value, NAME_EFFECT);
26
+ }
27
+ function isMora(value, name) {
28
+ return typeof value === "object" && value != null && "$mora" in value && (typeof name === "string" ? value["$mora"] === name : name.has(value["$mora"]));
29
+ }
30
+ /**
31
+ * Is the value reactive?
32
+ * @param value Value to check
33
+ * @returns True if value is a {@link Reactive}
34
+ */
35
+ function isReactive(value) {
36
+ return isMora(value, NAME_ALL);
37
+ }
38
+ /**
39
+ * Is the value a signal?
40
+ * @param value Value to check
41
+ * @returns True if value is a {@link Signal}
42
+ */
43
+ function isSignal(value) {
44
+ return isMora(value, NAME_SIGNAL);
45
+ }
46
+ /**
47
+ * Is the value a reactive store?
48
+ * @param value Value to check
49
+ * @returns True if value is a {@link Store}
50
+ */
51
+ function isStore(value) {
52
+ return isMora(value, NAME_STORE);
53
+ }
54
+ //#endregion
55
+ export { isArray, isComputed, isEffect, isReactive, isSignal, isStore };
@@ -0,0 +1,15 @@
1
+ import { Computed } from "../value/computed.mjs";
2
+ import { ReactiveState, SetValueInProxyParameters } from "../models.mjs";
3
+ import { ReactiveArray } from "../value/array.mjs";
4
+ import { Store } from "../value/store.mjs";
5
+ import { ArrayOrPlainObject, Key, PlainObject } from "@oscarpalmer/atoms/models";
6
+
7
+ //#region src/helpers/proxy.d.ts
8
+ declare function emityProxyValues<Value>(state: ReactiveState<Value, Value>, mapped: Map<Key, Computed<unknown>>): void;
9
+ declare function emityProxyValues<Value>(state: ReactiveState<Value[], Value>, mapped: Map<Key, Computed<unknown>>): void;
10
+ declare function getReactiveValueInProxy<Value>(array: ReactiveArray<Value>, mapped: Map<Key, Computed<unknown>>, index: number, isArray: true): Computed<unknown>;
11
+ declare function getReactiveValueInProxy<Value extends PlainObject>(store: Store<Value>, mapped: Map<Key, Computed<unknown>>, key: Key, isArray: false): Computed<unknown>;
12
+ declare function setProxyValue<Value, Item = Value>(array: boolean, state: ReactiveState<Value, Item>, isObject: (value: unknown) => value is Value | undefined, isProperty: (value: unknown) => boolean, setObject: (state: ReactiveState<Value, Item>, value: Value | undefined) => void, setProperty: (state: ReactiveState<Value, Item>, property: unknown, value: Item) => void, first?: unknown, second?: unknown): void;
13
+ declare function setValueInProxy<Value extends ArrayOrPlainObject, Equal>(parameters: SetValueInProxyParameters<Value, Equal>): boolean;
14
+ //#endregion
15
+ export { emityProxyValues, getReactiveValueInProxy, setProxyValue, setValueInProxy };
@@ -0,0 +1,72 @@
1
+ import "../constants.mjs";
2
+ import { computed } from "../value/computed.mjs";
3
+ import { emitValue } from "./value.mjs";
4
+ //#region src/helpers/proxy.ts
5
+ function emityProxyValues(state, mapped) {
6
+ const values = [...mapped.values()];
7
+ const { length } = values;
8
+ for (let index = 0; index < length; index += 1) values[index].effect.dirty = true;
9
+ emitValue(state);
10
+ }
11
+ function getReactiveValueInProxy(reactive, mapped, key, isArray) {
12
+ let item = mapped.get(key);
13
+ if (item == null) {
14
+ item = computed(() => isArray ? reactive.get().at(key) : reactive.get()[key]);
15
+ mapped.set(key, item);
16
+ }
17
+ return item;
18
+ }
19
+ function setProxyValue(array, state, isObject, isProperty, setObject, setProperty, first, second) {
20
+ if (array && first === "length") {
21
+ state.value.length = second;
22
+ return;
23
+ }
24
+ if (isObject(first)) {
25
+ setObject(state, first);
26
+ return;
27
+ }
28
+ const property = isProperty(first);
29
+ if (array && property && Number.isNaN(first)) return;
30
+ let actual = property ? second : first;
31
+ if (typeof actual === "function") try {
32
+ actual = actual();
33
+ } catch {
34
+ return;
35
+ }
36
+ if (actual instanceof Promise) {
37
+ if (property) {
38
+ state.promises ??= /* @__PURE__ */ new Map();
39
+ state.promises.set(first, actual);
40
+ } else state.promise = actual;
41
+ actual.then((value) => {
42
+ if (property && state.promises.get(first) === actual) {
43
+ state.promises.delete(first);
44
+ setProperty(state, first, value);
45
+ return;
46
+ }
47
+ if (!property && isObject(value) && state.promise === actual) {
48
+ state.promise = void 0;
49
+ setObject(state, value);
50
+ }
51
+ }).catch(() => {
52
+ if (property && state.promises.get(first) === actual) state.promises.delete(first);
53
+ else if (!property && state.promise === actual) state.promise = void 0;
54
+ });
55
+ } else if (property) setProperty(state, first, actual);
56
+ else if (isObject(actual)) setObject(state, actual);
57
+ }
58
+ function setValueInProxy(parameters) {
59
+ const { isArray, length, property, state, target, value } = parameters;
60
+ if (isArray) {
61
+ if (!(!Number.isNaN(Number(property)) || property === "length")) return Reflect.set(target, property, value);
62
+ }
63
+ const previous = Reflect.get(target, property);
64
+ if (!state.equal(previous, value)) {
65
+ Reflect.set(target, property, value);
66
+ emitValue(state);
67
+ if (isArray) length?.set(target.length);
68
+ }
69
+ return true;
70
+ }
71
+ //#endregion
72
+ export { emityProxyValues, getReactiveValueInProxy, setProxyValue, setValueInProxy };
@@ -0,0 +1,8 @@
1
+ import { ReactiveState } from "../models.mjs";
2
+
3
+ //#region src/helpers/value.d.ts
4
+ declare function emitValue<Value>(state: ReactiveState<Value, never>): void;
5
+ declare function equalArrays<Value>(state: ReactiveState<Value[], Value>, first: Value[], second: Value[]): boolean;
6
+ declare function getValue<Value>(state: ReactiveState<Value, never>): Value;
7
+ //#endregion
8
+ export { emitValue, equalArrays, getValue };
@@ -1,5 +1,6 @@
1
- import { ACTIVE, ARRAY_OFFSET, ARRAY_PEEK, ARRAY_THRESHOLD, BATCH } from "../constants.js";
2
- import { flushHandlers } from "../batch.js";
1
+ import { ACTIVE, BATCH } from "../constants.mjs";
2
+ import { flushHandlers } from "../batch.mjs";
3
+ //#region src/helpers/value.ts
3
4
  function emitValue(state) {
4
5
  for (const computed of state.computeds) computed.effect.dirty = true;
5
6
  for (const effect of state.effects) BATCH.handlers.add(effect);
@@ -24,4 +25,5 @@ function getValue(state) {
24
25
  if (ACTIVE.effect != null) state.effects.add(ACTIVE.effect);
25
26
  return state.value;
26
27
  }
28
+ //#endregion
27
29
  export { emitValue, equalArrays, getValue };
@@ -0,0 +1,10 @@
1
+ import { startBatch, stopBatch } from "./batch.mjs";
2
+ import { Effect, effect } from "./effect.mjs";
3
+ import { Reactive } from "./value/reactive.mjs";
4
+ import { Computed, computed } from "./value/computed.mjs";
5
+ import { Signal, signal } from "./value/signal.mjs";
6
+ import { Unsubscribe } from "./models.mjs";
7
+ import { ReactiveArray, array } from "./value/array.mjs";
8
+ import { Store, store } from "./value/store.mjs";
9
+ import { isArray, isComputed, isEffect, isReactive, isSignal } from "./helpers/is.mjs";
10
+ export { type Computed, type Effect, type Reactive, type ReactiveArray, type Signal, type Store, type Unsubscribe, array, computed, effect, isArray, isComputed, isEffect, isReactive, isSignal, signal, startBatch, stopBatch, store };
package/dist/index.mjs ADDED
@@ -0,0 +1,8 @@
1
+ import { effect } from "./effect.mjs";
2
+ import { isArray, isComputed, isEffect, isReactive, isSignal } from "./helpers/is.mjs";
3
+ import { startBatch, stopBatch } from "./batch.mjs";
4
+ import { computed } from "./value/computed.mjs";
5
+ import { signal } from "./value/signal.mjs";
6
+ import { array } from "./value/array.mjs";
7
+ import { store } from "./value/store.mjs";
8
+ export { array, computed, effect, isArray, isComputed, isEffect, isReactive, isSignal, signal, startBatch, stopBatch, store };
@@ -0,0 +1,62 @@
1
+ import { Effect } from "./effect.mjs";
2
+ import { Subscription } from "./subscription.mjs";
3
+ import { Computed } from "./value/computed.mjs";
4
+ import { Signal } from "./value/signal.mjs";
5
+ import { GenericCallback, Key } from "@oscarpalmer/atoms/models";
6
+
7
+ //#region src/models.d.ts
8
+ type Active = {
9
+ computed?: Computed<unknown>;
10
+ effect?: Effect;
11
+ };
12
+ type Batch = {
13
+ depth: number;
14
+ handlers: Set<Effect | Subscription>;
15
+ };
16
+ type ComputedEffect = {
17
+ dirty: boolean;
18
+ instance: Effect;
19
+ };
20
+ type EffectState = {
21
+ callback: GenericCallback;
22
+ };
23
+ type InternalComputed = {
24
+ readonly effect: ComputedEffect;
25
+ readonly state: ReactiveState<unknown, unknown>;
26
+ };
27
+ type InternalEffect = {
28
+ state: EffectState;
29
+ };
30
+ type ReactiveOptions<Value> = {
31
+ /**
32
+ * Method for comparing values for equality
33
+ * @param first First value
34
+ * @param second Second value
35
+ * @returns Are the values equal?
36
+ * @default Object.is
37
+ */
38
+ equal?: (first: Value, second: Value) => boolean;
39
+ };
40
+ type ReactiveState<Value, Equal> = {
41
+ computeds: Set<Computed<unknown>>;
42
+ effects: Set<Effect>;
43
+ equal: (first: Equal, second: Equal) => boolean;
44
+ promise?: Promise<Value>;
45
+ promises?: Map<Key, Promise<never>>;
46
+ subscriptions: Map<GenericCallback, Subscription>;
47
+ value: Value;
48
+ };
49
+ type SetValueInProxyParameters<Value, Equal> = {
50
+ target: Value;
51
+ property: PropertyKey;
52
+ value: unknown;
53
+ state: ReactiveState<Value, Equal>;
54
+ isArray: boolean;
55
+ length?: Signal<number>;
56
+ };
57
+ /**
58
+ * Unsubscribe from changes
59
+ */
60
+ type Unsubscribe = () => void;
61
+ //#endregion
62
+ export { Active, Batch, ComputedEffect, EffectState, InternalComputed, InternalEffect, ReactiveOptions, ReactiveState, SetValueInProxyParameters, Unsubscribe };
@@ -0,0 +1 @@
1
+ export {};