@oscarpalmer/mora 0.31.0 → 0.33.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 (58) hide show
  1. package/dist/batch.d.mts +4 -5
  2. package/dist/batch.mjs +4 -2
  3. package/dist/constants.d.mts +31 -19
  4. package/dist/constants.mjs +19 -2
  5. package/dist/effect.d.mts +5 -5
  6. package/dist/effect.mjs +8 -5
  7. package/dist/helpers/is.d.mts +14 -9
  8. package/dist/helpers/is.mjs +6 -0
  9. package/dist/helpers/misc.d.mts +4 -0
  10. package/dist/helpers/misc.mjs +9 -0
  11. package/dist/helpers/proxy.d.mts +10 -10
  12. package/dist/helpers/proxy.mjs +83 -27
  13. package/dist/helpers/subscription.d.mts +8 -0
  14. package/dist/helpers/subscription.mjs +30 -0
  15. package/dist/helpers/value.d.mts +10 -7
  16. package/dist/helpers/value.mjs +56 -17
  17. package/dist/index.d.mts +3 -2
  18. package/dist/models.d.mts +82 -101
  19. package/dist/models.mjs +1 -0
  20. package/dist/mora.full.mjs +659 -412
  21. package/dist/value/array.d.mts +5 -5
  22. package/dist/value/array.mjs +70 -109
  23. package/dist/value/computed.d.mts +5 -4
  24. package/dist/value/computed.mjs +45 -31
  25. package/dist/value/readonly.d.mts +4 -6
  26. package/dist/value/readonly.mjs +34 -31
  27. package/dist/value/signal.d.mts +5 -5
  28. package/dist/value/signal.mjs +28 -34
  29. package/dist/value/store.d.mts +5 -5
  30. package/dist/value/store.mjs +25 -83
  31. package/package.json +6 -6
  32. package/src/batch.ts +15 -5
  33. package/src/constants.ts +36 -2
  34. package/src/effect.ts +20 -11
  35. package/src/helpers/is.ts +16 -6
  36. package/src/helpers/misc.ts +15 -0
  37. package/src/helpers/proxy.ts +151 -74
  38. package/src/helpers/subscription.ts +89 -0
  39. package/src/helpers/value.ts +121 -30
  40. package/src/index.ts +1 -1
  41. package/src/models.ts +81 -98
  42. package/src/value/array.ts +116 -226
  43. package/src/value/computed.ts +96 -43
  44. package/src/value/readonly.ts +68 -54
  45. package/src/value/signal.ts +54 -46
  46. package/src/value/store.ts +42 -168
  47. package/types/constants.d.ts +1 -1
  48. package/types/index.d.ts +1 -1
  49. package/types/value/array.d.ts +1 -1
  50. package/types/value/computed.d.ts +0 -3
  51. package/types/value/signal.d.ts +1 -1
  52. package/types/value/store.d.ts +1 -1
  53. package/dist/subscription.d.mts +0 -7
  54. package/dist/subscription.mjs +0 -27
  55. package/dist/value/reactive.d.mts +0 -5
  56. package/dist/value/reactive.mjs +0 -16
  57. package/src/subscription.ts +0 -45
  58. package/src/value/reactive.ts +0 -24
@@ -1,5 +1,6 @@
1
1
  import { ReactiveArray, ReactiveOptions } from "../models.mjs";
2
2
  //#region src/value/array.d.ts
3
+ declare function ReactiveArray(this: any, value: unknown, options?: ReactiveOptions<unknown>): void;
3
4
  /**
4
5
  * Create a reactive array from a function result
5
6
  *
@@ -7,7 +8,7 @@ import { ReactiveArray, ReactiveOptions } from "../models.mjs";
7
8
  * @param options Reactivity options
8
9
  * @returns Reactive array
9
10
  */
10
- declare function array<Item>(value: () => Item[] | Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
11
+ export declare function array<Item>(value: () => Item[] | Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
11
12
  /**
12
13
  * Create a reactive array from a promise
13
14
  *
@@ -15,7 +16,7 @@ declare function array<Item>(value: () => Item[] | Promise<Item[]>, options?: Re
15
16
  * @param options Reactivity options
16
17
  * @returns Reactive array
17
18
  */
18
- declare function array<Item>(value: Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
19
+ export declare function array<Item>(value: Promise<Item[]>, options?: ReactiveOptions<Item>): ReactiveArray<Item>;
19
20
  /**
20
21
  * Create a reactive array
21
22
  *
@@ -23,6 +24,5 @@ declare function array<Item>(value: Promise<Item[]>, options?: ReactiveOptions<I
23
24
  * @param options Reactivity options
24
25
  * @returns Reactive array
25
26
  */
26
- declare function array<Item>(value: Item[], options?: ReactiveOptions<Item>): ReactiveArray<Item>;
27
- //#endregion
28
- export { array };
27
+ export declare function array<Item>(value: Item[], options?: ReactiveOptions<Item>): ReactiveArray<Item>;
28
+ //#endregion
@@ -1,135 +1,96 @@
1
- import { METHODS_AFFECTING_LENGTH, METHODS_UPDATE, NAME_ARRAY, NAME_MORA } from "../constants.mjs";
2
- import { emitValue, equalArrays, getSimpleValue } from "../helpers/value.mjs";
3
- import { subscribe, unsubscribe } from "../subscription.mjs";
4
- import { reactive } from "./reactive.mjs";
1
+ import { METHODS_AFFECTING_LENGTH, METHODS_UPDATE, NAME_ARRAY, NAME_MORA, PROPERTY_LENGTH, SYMBOL_STATE } from "../constants.mjs";
2
+ import { emitValue, equalArrays, getStringValue } from "../helpers/value.mjs";
3
+ import { getState } from "../helpers/misc.mjs";
4
+ import { subscribeToProxy } from "../helpers/subscription.mjs";
5
5
  import { computed } from "./computed.mjs";
6
- import { emityProxyValues, getReactiveValueInProxy, setProxyValue, setValueInProxy } from "../helpers/proxy.mjs";
6
+ import { emitProxyValues, getValueInProxy, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue } from "../helpers/proxy.mjs";
7
7
  import { getReadonlyInstance } from "./readonly.mjs";
8
8
  import { signal } from "./signal.mjs";
9
9
  import { select } from "@oscarpalmer/atoms/array";
10
10
  import { filter } from "@oscarpalmer/atoms/array/filter";
11
- import { noop } from "@oscarpalmer/atoms/function";
12
- import { isPlainObject } from "@oscarpalmer/atoms/is";
13
11
  //#region src/value/array.ts
14
- function array(value, options) {
15
- const [rx, state] = reactive([], options);
16
- const indiced = /* @__PURE__ */ new Map();
17
- const length = signal(0);
18
- const readonlies = {};
19
- let instance = {};
20
- state.value = new Proxy([], {
21
- get: (target, property) => METHODS_UPDATE.has(property) ? updateArray(property, target, state, length) : Reflect.get(target, property),
22
- set: (target, property, value) => setValueInProxy({
23
- length,
24
- property,
25
- state,
26
- target,
27
- value,
28
- isArray: true
29
- })
30
- });
31
- function get(value) {
32
- return getArrayValue(instance, indiced, state, length, value);
33
- }
34
- function set(first, second) {
35
- setProxyValue(true, state, isArrayValue, isArrayIndex, setArray, setAtIndex, first, second);
36
- }
37
- const handlers = {
38
- ...rx,
39
- get: (value) => get(value),
40
- peek: (first, second) => peekArrayValue(state, length, first, second),
41
- subscribe: (first, second) => {
42
- if (typeof first === "number" && typeof second === "function") return getReactiveValueInProxy(instance, indiced, first, true).subscribe(second);
43
- return typeof first === "function" ? subscribe(state, first) : noop;
44
- },
45
- unsubscribe: (first, second) => {
46
- if (typeof first === "number" && typeof second === "function") getReactiveValueInProxy(instance, indiced, first, true)?.unsubscribe(second);
47
- else if (typeof first === "function") unsubscribe(state, first);
48
- }
12
+ function ReactiveArray(value, options) {
13
+ this[SYMBOL_STATE] = {
14
+ ...getState(void 0, options),
15
+ isArray: true,
16
+ length: signal(0)
49
17
  };
50
- instance = {
51
- ...handlers,
52
- asReadonly: (frozen) => getReadonlyInstance(state, readonlies, handlers, frozen === true),
53
- at: (index) => get(index),
54
- clear: () => {
55
- state.value.length = 0;
56
- },
57
- filter: (callback) => computed(() => filter(get(), callback)),
58
- map: (callback) => computed(() => get().map(callback)),
59
- notify: () => {
60
- emityProxyValues(state, indiced);
61
- },
62
- pop: () => state.value.pop(),
63
- push: (...items) => state.value.push(...items),
64
- select: (filter, map) => computed(() => select(get(), filter, map)),
65
- set: (first, second) => {
66
- set(first, second);
67
- },
68
- shift: () => state.value.shift(),
69
- splice: (from, to, ...items) => state.value.splice(from, to ?? state.value.length, ...items),
70
- unshift: (...items) => state.value.unshift(...items),
71
- update: (callback) => updateArrayValue(instance, state, callback)
72
- };
73
- Object.defineProperties(instance, {
74
- [NAME_MORA]: {
75
- enumerable: false,
76
- value: NAME_ARRAY
77
- },
78
- length: {
79
- enumerable: true,
80
- get: () => length.get(),
81
- set: (value) => setArrayLength(state, value)
82
- }
18
+ this[SYMBOL_STATE].value = new Proxy([], {
19
+ get: (target, property) => METHODS_UPDATE.has(property) ? updateArray(this, property, target) : Reflect.get(target, property),
20
+ set: (target, property, value) => setValueInProxy(this, target, property, value)
83
21
  });
84
- set(value);
85
- return Object.freeze(instance);
86
- }
87
- function getArrayValue(instance, indiced, state, length, first) {
88
- if (typeof first === "number") return getReactiveValueInProxy(instance, indiced, first, true).get();
89
- return first === "length" ? length.get() : getSimpleValue(state);
90
- }
91
- function isArrayIndex(value) {
92
- return typeof value === "number";
22
+ Object.defineProperty(this, PROPERTY_LENGTH, {
23
+ enumerable: true,
24
+ get: () => this[SYMBOL_STATE].length.get(),
25
+ set: (value) => setArrayLength(this[SYMBOL_STATE], value)
26
+ });
27
+ setProxyValue.call(this, value);
93
28
  }
94
- function isArrayValue(value) {
95
- return value == null || Array.isArray(value);
29
+ ReactiveArray.prototype[NAME_MORA] = NAME_ARRAY;
30
+ ReactiveArray.prototype.asReadonly = getReadonlyInstance;
31
+ ReactiveArray.prototype.at = getArrayValues;
32
+ ReactiveArray.prototype.get = getArrayValues;
33
+ ReactiveArray.prototype.notify = emitProxyValues;
34
+ ReactiveArray.prototype.peek = peekArrayValue;
35
+ ReactiveArray.prototype.set = setProxyValue;
36
+ ReactiveArray.prototype.subscribe = subscribeToProxy;
37
+ ReactiveArray.prototype.toString = getStringValue;
38
+ ReactiveArray.prototype.update = updateProxyValue;
39
+ ReactiveArray.prototype.clear = function() {
40
+ this[SYMBOL_STATE].value.length = 0;
41
+ };
42
+ ReactiveArray.prototype.filter = function(callback) {
43
+ return computed(() => filter(getArrayValues.call(this), callback));
44
+ };
45
+ ReactiveArray.prototype.map = function(callback) {
46
+ return computed(() => getArrayValues.call(this).map(callback));
47
+ };
48
+ ReactiveArray.prototype.pop = function() {
49
+ return this[SYMBOL_STATE].value.pop();
50
+ };
51
+ ReactiveArray.prototype.push = function(...items) {
52
+ return this[SYMBOL_STATE].value.push(...items);
53
+ };
54
+ ReactiveArray.prototype.select = function(filter, map) {
55
+ return computed(() => select(getArrayValues.call(this), filter, map));
56
+ };
57
+ ReactiveArray.prototype.shift = function() {
58
+ return this[SYMBOL_STATE].value.shift();
59
+ };
60
+ ReactiveArray.prototype.splice = function(from, to, ...items) {
61
+ return this[SYMBOL_STATE].value.splice(from, to ?? this[SYMBOL_STATE].value.length, ...items);
62
+ };
63
+ ReactiveArray.prototype.toJSON = function() {
64
+ return this[SYMBOL_STATE].value;
65
+ };
66
+ ReactiveArray.prototype.unshift = function(...items) {
67
+ return this[SYMBOL_STATE].value.unshift(...items);
68
+ };
69
+ function array(value, options) {
70
+ return new ReactiveArray(value, options);
96
71
  }
97
- function peekArrayValue(state, length, first, second) {
98
- if (first === "length") return length.peek();
99
- let value;
100
- if (typeof first === "number") value = state.value.at(first);
101
- else value = state.value;
102
- if (!(first === true || second === true)) return value;
103
- if (Array.isArray(value)) return value.slice();
104
- if (isPlainObject(value)) return { ...value };
105
- return value;
72
+ function getArrayValues(value) {
73
+ return value === "length" ? this[SYMBOL_STATE].length.get() : getValueInProxy.call(this, value);
106
74
  }
107
- function setArray(state, value) {
108
- state.value.splice(0, state.value.length, ...value ?? []);
75
+ function peekArrayValue(first, second) {
76
+ return first === "length" ? this[SYMBOL_STATE].length.peek() : peekValueInProxy.call(this, first, second);
109
77
  }
110
78
  function setArrayLength(state, value) {
111
- if (typeof value === "number" && value >= 0 && value !== state.value.length) state.value.length = value;
79
+ if (typeof value === "number" && !Number.isNaN(value) && value >= 0 && value !== state.value.length) state.value.length = value;
112
80
  }
113
- function setAtIndex(state, index, value) {
114
- const actual = index < 0 ? state.value.length + index : index;
115
- if (actual > -1) state.value[actual] = value;
116
- }
117
- function updateArray(type, array, state, length) {
81
+ function updateArray(instance, type, array) {
82
+ const state = instance[SYMBOL_STATE];
118
83
  const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
119
84
  const previousArray = affectsLength ? [] : array.slice();
120
85
  const previousLength = array.length;
121
86
  return (...args) => {
122
87
  const result = array[type](...args);
123
88
  if (affectsLength ? array.length !== previousLength : !equalArrays(state, previousArray, array)) {
124
- emitValue(state);
125
- length.set(array.length);
89
+ emitValue(instance);
90
+ state.length.set(array.length);
126
91
  }
127
92
  return result;
128
93
  };
129
94
  }
130
- function updateArrayValue(instance, state, callback) {
131
- const updated = callback(state.value);
132
- if (updated == null || Array.isArray(updated)) instance.set(updated);
133
- }
134
95
  //#endregion
135
96
  export { array };
@@ -1,5 +1,7 @@
1
1
  import { Computed, ComputedEffect, ReactiveOptions } from "../models.mjs";
2
+ import { GenericCallback } from "@oscarpalmer/atoms/models";
2
3
  //#region src/value/computed.d.ts
4
+ declare function Computed(this: any, callback: GenericCallback, options?: ReactiveOptions<unknown>): void;
3
5
  /**
4
6
  * Create a computed value
5
7
  *
@@ -7,7 +9,6 @@ import { Computed, ComputedEffect, ReactiveOptions } from "../models.mjs";
7
9
  * @param options Reactivity options
8
10
  * @returns Computed value
9
11
  */
10
- declare function computed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Computed<Value>;
11
- declare function internalComputed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): [Computed<Value>, ComputedEffect];
12
- //#endregion
13
- export { computed, internalComputed };
12
+ export declare function computed<Value>(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Computed<Value>;
13
+ export declare function internalComputed(callback: GenericCallback, options?: ReactiveOptions<unknown>): [Computed<unknown>, ComputedEffect];
14
+ //#endregion
@@ -1,10 +1,22 @@
1
- import { ACTIVE, BATCH, NAME_COMPUTED, NAME_MORA } from "../constants.mjs";
1
+ import { ACTIVE, BATCH, NAME_COMPUTED, NAME_MORA, SUBSCRIPTION_TYPES, SUBSCRIPTION_TYPES_COPY, SYMBOL_EFFECT, SYMBOL_STATE } from "../constants.mjs";
2
2
  import { internalEffect, runEffect } from "../effect.mjs";
3
+ import { getStringValue, handleSignalValue, peekSignalValue } from "../helpers/value.mjs";
3
4
  import { flushHandlers } from "../batch.mjs";
4
- import { handleSimpleValue } from "../helpers/value.mjs";
5
- import { subscribe } from "../subscription.mjs";
6
- import { reactive } from "./reactive.mjs";
5
+ import { getState } from "../helpers/misc.mjs";
6
+ import { subscribeToSignal } from "../helpers/subscription.mjs";
7
7
  //#region src/value/computed.ts
8
+ function Computed(callback, options) {
9
+ this[SYMBOL_STATE] = getState(void 0, options);
10
+ this[SYMBOL_EFFECT] = getComputedEffect(this, callback);
11
+ }
12
+ Computed.prototype[NAME_MORA] = NAME_COMPUTED;
13
+ Computed.prototype.get = getComputedValue;
14
+ Computed.prototype.peek = peekSignalValue;
15
+ Computed.prototype.subscribe = subscribeToSignal;
16
+ Computed.prototype.toString = getStringValue;
17
+ Computed.prototype.toJSON = function() {
18
+ return this[SYMBOL_STATE].value;
19
+ };
8
20
  /**
9
21
  * Create a computed value
10
22
  *
@@ -16,25 +28,11 @@ function computed(callback, options) {
16
28
  return getComputed(callback, options)[0];
17
29
  }
18
30
  function getComputed(callback, options) {
19
- const [rx, state] = reactive(void 0, options);
20
- let fx;
21
- const instance = {
22
- ...rx,
23
- get: () => getValue(state, fx),
24
- peek: () => state.value,
25
- subscribe: (callback) => subscribe(state, callback),
26
- unsubscribe: (callback) => {
27
- state.subscriptions.delete(callback);
28
- }
29
- };
30
- Object.defineProperty(instance, NAME_MORA, {
31
- enumerable: false,
32
- value: NAME_COMPUTED
33
- });
34
- fx = getComputedEffect(state, callback);
35
- return [Object.freeze(instance), fx];
31
+ if (typeof callback !== "function") throw new TypeError("Computed callback must be a function");
32
+ const instance = new Computed(callback, options);
33
+ return [instance, instance[SYMBOL_EFFECT]];
36
34
  }
37
- function getComputedEffect(state, callback) {
35
+ function getComputedEffect(instance, callback) {
38
36
  const fx = {
39
37
  dirty: true,
40
38
  instance: void 0
@@ -43,7 +41,7 @@ function getComputedEffect(state, callback) {
43
41
  if (fx.dirty) {
44
42
  const previousComputed = ACTIVE.computed;
45
43
  ACTIVE.computed = fx;
46
- handleSimpleValue(state, callback, setAndEmit, () => {
44
+ handleSignalValue(instance, callback, setAndEmit, () => {
47
45
  ACTIVE.computed = previousComputed;
48
46
  });
49
47
  fx.dirty = false;
@@ -51,21 +49,37 @@ function getComputedEffect(state, callback) {
51
49
  });
52
50
  return fx;
53
51
  }
54
- function getValue(state, fx) {
55
- if (ACTIVE.computed != null && fx !== ACTIVE.computed) state.computeds.add(ACTIVE.computed);
56
- if (ACTIVE.effect != null && ACTIVE.effect !== fx.instance) state.effects.add(ACTIVE.effect);
52
+ function getComputedValue() {
53
+ const fx = this[SYMBOL_EFFECT];
54
+ const state = this[SYMBOL_STATE];
55
+ if (ACTIVE.computed != null && fx !== ACTIVE.computed) {
56
+ state.computeds ??= /* @__PURE__ */ new Set();
57
+ state.computeds.add(ACTIVE.computed);
58
+ }
59
+ if (ACTIVE.effect != null && ACTIVE.effect !== fx.instance) {
60
+ state.effects ??= /* @__PURE__ */ new Set();
61
+ state.effects.add(ACTIVE.effect);
62
+ }
57
63
  if (fx.dirty && BATCH.depth === 0) runEffect(fx.instance);
58
64
  return state.value;
59
65
  }
60
66
  function internalComputed(callback, options) {
61
67
  return getComputed(callback, options);
62
68
  }
63
- function setAndEmit(state, value) {
64
- if (state.equal(state.value, value)) return;
69
+ function setAndEmit(instance, value) {
70
+ const state = instance[SYMBOL_STATE];
71
+ if ((state.equal ?? Object.is)(state.value, value)) return;
65
72
  state.value = value;
66
- for (const computed of state.computeds) computed.dirty = true;
67
- for (const effect of state.effects) BATCH.handlers.add(effect);
68
- for (const [, subscription] of state.subscriptions) subscription.callback(value);
73
+ if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
74
+ if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) BATCH.handlers.set(effect, effect);
75
+ for (const type of SUBSCRIPTION_TYPES) {
76
+ if (type === "frozen") continue;
77
+ const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
78
+ if (subscriptions != null && subscriptions.size > 0) {
79
+ const copy = SUBSCRIPTION_TYPES_COPY.has(type);
80
+ for (const [, callback] of subscriptions) callback(peekSignalValue.call(instance, copy));
81
+ }
82
+ }
69
83
  flushHandlers();
70
84
  }
71
85
  //#endregion
@@ -1,7 +1,5 @@
1
- import { ReactiveState, ReadonlyFrozenSignal, ReadonlyInstances, ReadonlySignal } from "../models.mjs";
2
- import { GenericCallback } from "@oscarpalmer/atoms/models";
1
+ import { InternalSignal, ReadonlyFrozenSignal, ReadonlySignal, SignalState } from "../models.mjs";
3
2
  //#region src/value/readonly.d.ts
4
- declare function getReadonlyInstance<Value>(state: ReactiveState<Value, never>, instances: ReadonlyInstances<Value>, handlers: Record<string, GenericCallback>, frozen: boolean): ReadonlySignal<Value>;
5
- declare function getReadonlySignal<Value>(state: ReactiveState<Value, never>, handlers: Record<string, GenericCallback>, frozen: boolean): ReadonlySignal<Value> | ReadonlyFrozenSignal<Value>;
6
- //#endregion
7
- export { getReadonlyInstance, getReadonlySignal };
3
+ export declare function getReadonlyInstance<Value>(this: InternalSignal, frozen?: never): ReadonlySignal<Value>;
4
+ export declare function getReadonlySignal(state: SignalState, frozen: boolean): ReadonlySignal<unknown> | ReadonlyFrozenSignal<unknown>;
5
+ //#endregion
@@ -1,37 +1,40 @@
1
- import { NAME_MORA, NAME_READONLY } from "../constants.mjs";
2
- import { getSimpleValue } from "../helpers/value.mjs";
3
- import { isPlainObject } from "@oscarpalmer/atoms/is";
1
+ import { NAME_MORA, NAME_READONLY, SUBSCRIPTION_TYPE_FROZEN, SUBSCRIPTION_TYPE_ORIGINAL, SYMBOL_STATE } from "../constants.mjs";
2
+ import { getFrozenValue, getSignalValue, getStringValue, peekSignalValue } from "../helpers/value.mjs";
3
+ import { subscribeToReadonly } from "../helpers/subscription.mjs";
4
4
  //#region src/value/readonly.ts
5
- function getReadonlyInstance(state, instances, handlers, frozen) {
6
- const key = frozen ? "frozen" : "original";
7
- instances[key] ??= getReadonlySignal(state, handlers, frozen);
8
- return instances[key];
9
- }
10
- function getReadonlySignal(state, handlers, frozen) {
11
- const instance = {
12
- ...handlers,
13
- get: () => getReadonlyValue(state, false, frozen),
14
- peek: () => getReadonlyValue(state, true, frozen)
15
- };
16
- Object.defineProperties(instance, {
17
- [NAME_MORA]: {
18
- enumerable: false,
19
- value: NAME_READONLY
20
- },
21
- frozen: {
22
- enumerable: true,
23
- value: frozen
24
- }
5
+ function Readonly(state, frozen) {
6
+ this[SYMBOL_STATE] = state;
7
+ Object.defineProperty(this, SUBSCRIPTION_TYPE_FROZEN, {
8
+ enumerable: true,
9
+ value: frozen
25
10
  });
26
- return Object.freeze(instance);
27
11
  }
28
- function getReadonlyValue(state, peek, frozen) {
29
- let value = peek ? state.value : getSimpleValue(state);
30
- if (!frozen) return value;
31
- if (Array.isArray(state.value)) value = [...state.value];
32
- else if (isPlainObject(state.value)) value = { ...state.value };
33
- else value = state.value;
34
- return Object.freeze(value);
12
+ Readonly.prototype[NAME_MORA] = NAME_READONLY;
13
+ Readonly.prototype.subscribe = subscribeToReadonly;
14
+ Readonly.prototype.toString = getStringValue;
15
+ Readonly.prototype.get = function() {
16
+ return getReadonlyValue(this, false, this[SUBSCRIPTION_TYPE_FROZEN]);
17
+ };
18
+ Readonly.prototype.peek = function(copy) {
19
+ return getReadonlyValue(this, true, this[SUBSCRIPTION_TYPE_FROZEN], copy);
20
+ };
21
+ Readonly.prototype.toJSON = function() {
22
+ return this[SYMBOL_STATE].value;
23
+ };
24
+ function getReadonlyInstance(frozen) {
25
+ const key = frozen === true ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_ORIGINAL;
26
+ this[SYMBOL_STATE].readonlies ??= {};
27
+ this[SYMBOL_STATE].readonlies[key] ??= getReadonlySignal(this[SYMBOL_STATE], frozen === true);
28
+ return this[SYMBOL_STATE].readonlies[key];
29
+ }
30
+ function getReadonlySignal(state, frozen) {
31
+ return new Readonly(state, frozen);
32
+ }
33
+ function getReadonlyValue(instance, peek, frozen, copy) {
34
+ let value;
35
+ if (peek) value = peekSignalValue.call(instance, copy === true);
36
+ else value = getSignalValue.call(instance);
37
+ return frozen ? getFrozenValue(value) : value;
35
38
  }
36
39
  //#endregion
37
40
  export { getReadonlyInstance, getReadonlySignal };
@@ -1,5 +1,6 @@
1
1
  import { ReactiveOptions, Signal } from "../models.mjs";
2
2
  //#region src/value/signal.d.ts
3
+ declare function Signal(this: any, value: unknown, options?: ReactiveOptions<unknown>): void;
3
4
  /**
4
5
  * Create a reactive value from a function result
5
6
  *
@@ -7,7 +8,7 @@ import { ReactiveOptions, Signal } from "../models.mjs";
7
8
  * @param options Reactivity options
8
9
  * @returns Reactive value
9
10
  */
10
- declare function signal<Value>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
11
+ export declare function signal<Value>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
11
12
  /**
12
13
  * Create a reactive value from a promise
13
14
  *
@@ -15,7 +16,7 @@ declare function signal<Value>(value: () => Value | Promise<Value>, options?: Re
15
16
  * @param options Reactivity options
16
17
  * @returns Reactive value
17
18
  */
18
- declare function signal<Value>(value: Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
19
+ export declare function signal<Value>(value: Promise<Value>, options?: ReactiveOptions<Value>): Signal<Value>;
19
20
  /**
20
21
  * Create a reactive value
21
22
  *
@@ -23,6 +24,5 @@ declare function signal<Value>(value: Promise<Value>, options?: ReactiveOptions<
23
24
  * @param options Reactivity options
24
25
  * @returns Reactive value
25
26
  */
26
- declare function signal<Value>(value: Value, options?: ReactiveOptions<Value>): Signal<Value>;
27
- //#endregion
28
- export { signal };
27
+ export declare function signal<Value>(value: Value, options?: ReactiveOptions<Value>): Signal<Value>;
28
+ //#endregion
@@ -1,43 +1,37 @@
1
- import { NAME_MORA, NAME_SIGNAL } from "../constants.mjs";
2
- import { emitValue, getSimpleValue, handleSimpleValue } from "../helpers/value.mjs";
3
- import { subscribe } from "../subscription.mjs";
4
- import { reactive } from "./reactive.mjs";
1
+ import { NAME_MORA, NAME_SIGNAL, SYMBOL_STATE } from "../constants.mjs";
2
+ import { emitValue, getSignalValue, getStringValue, handleSignalValue, peekSignalValue, updateSignalValue } from "../helpers/value.mjs";
3
+ import { getState } from "../helpers/misc.mjs";
4
+ import { subscribeToSignal } from "../helpers/subscription.mjs";
5
5
  import { getReadonlyInstance } from "./readonly.mjs";
6
6
  //#region src/value/signal.ts
7
- function setAndEmit(state, value) {
8
- if (!state.equal(state.value, value)) {
7
+ function Signal(value, options) {
8
+ this[SYMBOL_STATE] = getState(void 0, options);
9
+ handleSignalValue(this, value, setAndEmit);
10
+ }
11
+ Signal.prototype[NAME_MORA] = NAME_SIGNAL;
12
+ Signal.prototype.asReadonly = getReadonlyInstance;
13
+ Signal.prototype.get = getSignalValue;
14
+ Signal.prototype.peek = peekSignalValue;
15
+ Signal.prototype.subscribe = subscribeToSignal;
16
+ Signal.prototype.toString = getStringValue;
17
+ Signal.prototype.set = function(value) {
18
+ return handleSignalValue(this, value, setAndEmit);
19
+ };
20
+ Signal.prototype.toJSON = function() {
21
+ return this[SYMBOL_STATE].value;
22
+ };
23
+ Signal.prototype.update = function(callback) {
24
+ return updateSignalValue(this, callback, setAndEmit);
25
+ };
26
+ function setAndEmit(instance, value) {
27
+ const state = instance[SYMBOL_STATE];
28
+ if (!(state.equal ?? Object.is)(state.value, value)) {
9
29
  state.value = value;
10
- emitValue(state);
30
+ emitValue(instance);
11
31
  }
12
32
  }
13
33
  function signal(value, options) {
14
- const [rx, state] = reactive(void 0, options);
15
- const readonlies = {};
16
- const handlers = {
17
- ...rx,
18
- subscribe: (callback) => subscribe(state, callback),
19
- unsubscribe: (callback) => {
20
- state.subscriptions.delete(callback);
21
- }
22
- };
23
- const instance = {
24
- ...handlers,
25
- asReadonly: (frozen) => getReadonlyInstance(state, readonlies, handlers, frozen === true),
26
- get: () => getSimpleValue(state),
27
- peek: () => state.value,
28
- set: (value) => {
29
- handleSimpleValue(state, value, setAndEmit);
30
- },
31
- update: (callback) => {
32
- handleSimpleValue(state, callback(state.value), setAndEmit);
33
- }
34
- };
35
- Object.defineProperty(instance, NAME_MORA, {
36
- enumerable: false,
37
- value: NAME_SIGNAL
38
- });
39
- handleSimpleValue(state, value, setAndEmit);
40
- return Object.freeze(instance);
34
+ return new Signal(value, options);
41
35
  }
42
36
  //#endregion
43
37
  export { signal };
@@ -1,6 +1,7 @@
1
1
  import { ReactiveOptions, ReactiveStore } from "../models.mjs";
2
2
  import { PlainObject } from "@oscarpalmer/atoms/models";
3
3
  //#region src/value/store.d.ts
4
+ declare function ReactiveStore(this: any, value: never, options?: ReactiveOptions<unknown>): void;
4
5
  /**
5
6
  * Create a reactive store from a function result
6
7
  *
@@ -8,7 +9,7 @@ import { PlainObject } from "@oscarpalmer/atoms/models";
8
9
  * @param options Reactivity options
9
10
  * @returns Reactive store
10
11
  */
11
- declare function store<Value extends PlainObject>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
12
+ export declare function store<Value extends PlainObject>(value: () => Value | Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
12
13
  /**
13
14
  * Create a reactive store from a promise
14
15
  *
@@ -16,7 +17,7 @@ declare function store<Value extends PlainObject>(value: () => Value | Promise<V
16
17
  * @param options Reactivity options
17
18
  * @returns Reactive store
18
19
  */
19
- declare function store<Value extends PlainObject>(value: Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
20
+ export declare function store<Value extends PlainObject>(value: Promise<Value>, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
20
21
  /**
21
22
  * Create a reactive store
22
23
  *
@@ -24,6 +25,5 @@ declare function store<Value extends PlainObject>(value: Promise<Value>, options
24
25
  * @param options Reactivity options
25
26
  * @returns Reactive store
26
27
  */
27
- declare function store<Value extends PlainObject>(value: Value, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
28
- //#endregion
29
- export { store };
28
+ export declare function store<Value extends PlainObject>(value: Value, options?: ReactiveOptions<Value>): ReactiveStore<Value>;
29
+ //#endregion