@fluixi/reactive 1.0.0-alpha.105 → 1.0.0-alpha.106
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdn/reactive.cjs +74 -34
- package/dist/cdn/reactive.global.js +2 -2
- package/dist/cdn/reactive.mjs +74 -34
- package/dist/cdn/signal.cjs +23 -3
- package/dist/cdn/signal.global.js +2 -2
- package/dist/cdn/signal.mjs +23 -3
- package/dist/index.cjs +74 -34
- package/dist/index.mjs +74 -34
- package/dist/lib/index.cjs +75 -35
- package/dist/lib/index.mjs +75 -35
- package/dist/lib/observable/index.cjs +1 -1
- package/dist/lib/observable/index.mjs +1 -1
- package/dist/lib/signal/api.cjs +40 -14
- package/dist/lib/signal/api.mjs +40 -14
- package/dist/lib/signal/cached-resource.cjs +36 -13
- package/dist/lib/signal/cached-resource.mjs +36 -13
- package/dist/lib/signal/graph/children.cjs +25 -6
- package/dist/lib/signal/graph/children.mjs +25 -6
- package/dist/lib/signal/graph/compat.cjs +41 -15
- package/dist/lib/signal/graph/compat.d.ts.map +1 -1
- package/dist/lib/signal/graph/compat.js +20 -11
- package/dist/lib/signal/graph/compat.mjs +41 -15
- package/dist/lib/signal/graph/context-children.cjs +1 -1
- package/dist/lib/signal/graph/context-children.mjs +1 -1
- package/dist/lib/signal/graph/core.cjs +24 -4
- package/dist/lib/signal/graph/core.d.ts +10 -0
- package/dist/lib/signal/graph/core.d.ts.map +1 -1
- package/dist/lib/signal/graph/core.js +27 -2
- package/dist/lib/signal/graph/core.mjs +24 -4
- package/dist/lib/signal/graph/debounced.cjs +35 -12
- package/dist/lib/signal/graph/debounced.mjs +35 -12
- package/dist/lib/signal/graph/derived.cjs +35 -12
- package/dist/lib/signal/graph/derived.mjs +35 -12
- package/dist/lib/signal/graph/detect.cjs +1 -1
- package/dist/lib/signal/graph/detect.mjs +1 -1
- package/dist/lib/signal/graph/error-boundary.cjs +10 -8
- package/dist/lib/signal/graph/error-boundary.mjs +10 -8
- package/dist/lib/signal/graph/index.cjs +24 -4
- package/dist/lib/signal/graph/index.mjs +24 -4
- package/dist/lib/signal/graph/observe.cjs +1 -1
- package/dist/lib/signal/graph/observe.mjs +1 -1
- package/dist/lib/signal/graph/resource.cjs +35 -12
- package/dist/lib/signal/graph/resource.mjs +35 -12
- package/dist/lib/signal/graph/runtime.cjs +29 -5
- package/dist/lib/signal/graph/runtime.d.ts.map +1 -1
- package/dist/lib/signal/graph/runtime.js +5 -3
- package/dist/lib/signal/graph/runtime.mjs +29 -5
- package/dist/lib/signal/graph/signal-next.cjs +67 -29
- package/dist/lib/signal/graph/signal-next.mjs +67 -29
- package/dist/lib/signal/graph/state.cjs +1 -1
- package/dist/lib/signal/graph/state.mjs +1 -1
- package/dist/lib/signal/graph/suspense.cjs +10 -8
- package/dist/lib/signal/graph/suspense.mjs +10 -8
- package/dist/lib/signal/index-legacy.cjs +67 -29
- package/dist/lib/signal/index-legacy.mjs +67 -29
- package/dist/lib/signal/index.cjs +67 -29
- package/dist/lib/signal/index.mjs +67 -29
- package/dist/lib/signal/list.cjs +58 -25
- package/dist/lib/signal/list.d.ts +3 -8
- package/dist/lib/signal/list.d.ts.map +1 -1
- package/dist/lib/signal/list.js +40 -18
- package/dist/lib/signal/list.mjs +58 -25
- package/dist/lib/signal/resource-api.cjs +35 -12
- package/dist/lib/signal/resource-api.mjs +35 -12
- package/dist/lib/signal/signal.cjs +41 -15
- package/dist/lib/signal/signal.mjs +41 -15
- package/dist/lib/signal/utilities.cjs +41 -15
- package/dist/lib/signal/utilities.mjs +41 -15
- package/dist/lib/store/api.cjs +9 -7
- package/dist/lib/store/api.mjs +9 -7
- package/dist/lib/store/index.cjs +10 -8
- package/dist/lib/store/index.mjs +10 -8
- package/dist/lib/store/store.cjs +9 -7
- package/dist/lib/store/store.d.ts.map +1 -1
- package/dist/lib/store/store.js +8 -6
- package/dist/lib/store/store.mjs +9 -7
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/version.generated.cjs +2 -2
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/dist/version.generated.mjs +2 -2
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/version.generated.ts
|
|
2
|
-
var VERSION = "1.0.0-alpha.
|
|
2
|
+
var VERSION = "1.0.0-alpha.106";
|
|
3
3
|
|
|
4
4
|
// src/lib/predicates.ts
|
|
5
5
|
function isFunction(value) {
|
|
@@ -636,6 +636,7 @@ var Computed = class extends Source {
|
|
|
636
636
|
super();
|
|
637
637
|
this._threw = false;
|
|
638
638
|
this._initialized = false;
|
|
639
|
+
this._disposed = false;
|
|
639
640
|
this.state = DIRTY;
|
|
640
641
|
/** Nodes this computation read on its last run. Rebuilt on every run. */
|
|
641
642
|
this.sources = null;
|
|
@@ -651,8 +652,23 @@ var Computed = class extends Source {
|
|
|
651
652
|
if (this._threw) throw this._error;
|
|
652
653
|
return this._value;
|
|
653
654
|
}
|
|
655
|
+
/**
|
|
656
|
+
* Unlink from every source, for good. Without this, a source outlives the
|
|
657
|
+
* computation and keeps it (and everything its function captured) reachable
|
|
658
|
+
* through its observers set: a disposed list row stayed in memory that way.
|
|
659
|
+
* The last value stays readable; the node simply never updates again.
|
|
660
|
+
*/
|
|
661
|
+
dispose() {
|
|
662
|
+
if (this._disposed) return;
|
|
663
|
+
this._disposed = true;
|
|
664
|
+
if (this.sources) {
|
|
665
|
+
for (const s of this.sources) s.observers?.delete(this);
|
|
666
|
+
this.sources = null;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
654
669
|
/** Settle, if CHECK, verify sources; if DIRTY (or never run), recompute. */
|
|
655
670
|
updateIfNecessary() {
|
|
671
|
+
if (this._disposed) return;
|
|
656
672
|
if (this.state === CHECK) {
|
|
657
673
|
if (this.sources) {
|
|
658
674
|
for (const s of this.sources) {
|
|
@@ -696,7 +712,7 @@ var Computed = class extends Source {
|
|
|
696
712
|
reportReactiveRun(this);
|
|
697
713
|
if (changed) {
|
|
698
714
|
this.version++;
|
|
699
|
-
if (this.observers) for (const o of
|
|
715
|
+
if (this.observers) for (const o of this.observers) o.markDirty(DIRTY);
|
|
700
716
|
notifyWatchers(this);
|
|
701
717
|
}
|
|
702
718
|
}
|
|
@@ -710,7 +726,7 @@ var Computed = class extends Source {
|
|
|
710
726
|
const wasClean = this.state === CLEAN;
|
|
711
727
|
this.state = level;
|
|
712
728
|
if (wasClean) {
|
|
713
|
-
if (this.observers) for (const o of
|
|
729
|
+
if (this.observers) for (const o of this.observers) o.markDirty(CHECK);
|
|
714
730
|
notifyWatchers(this);
|
|
715
731
|
}
|
|
716
732
|
}
|
|
@@ -749,6 +765,10 @@ var Watcher = class {
|
|
|
749
765
|
this._pending.clear();
|
|
750
766
|
return out;
|
|
751
767
|
}
|
|
768
|
+
/** Drain pending without the array, for callers that only need it empty. */
|
|
769
|
+
clearPending() {
|
|
770
|
+
this._pending.clear();
|
|
771
|
+
}
|
|
752
772
|
/** @internal, a watched node became non-clean. Edge-triggered: notify once. */
|
|
753
773
|
_notify(node) {
|
|
754
774
|
if (!this._watched.has(node) || this._pending.has(node)) return;
|
|
@@ -966,14 +986,14 @@ var EffectNode = class {
|
|
|
966
986
|
if (typeof r === "function") (this.owner.cleanups ??= []).push(r);
|
|
967
987
|
});
|
|
968
988
|
});
|
|
969
|
-
reportReactiveNode({ kind: "effect", node: this.computed, handle: this, internal: !report, ...name ? { name } : {} });
|
|
989
|
+
if (isObserved()) reportReactiveNode({ kind: "effect", node: this.computed, handle: this, internal: !report, ...name ? { name } : {} });
|
|
970
990
|
this.watcher = new Watcher(() => enqueue(this));
|
|
971
991
|
this.run();
|
|
972
992
|
this.watcher.watch(this.computed);
|
|
973
993
|
}
|
|
974
994
|
run() {
|
|
975
995
|
if (this.disposed) return;
|
|
976
|
-
this.watcher.
|
|
996
|
+
this.watcher.clearPending();
|
|
977
997
|
try {
|
|
978
998
|
this.computed.get();
|
|
979
999
|
} catch (e) {
|
|
@@ -990,6 +1010,7 @@ var EffectNode = class {
|
|
|
990
1010
|
this.disposed = true;
|
|
991
1011
|
reportReactiveDispose(this.computed);
|
|
992
1012
|
this.watcher.unwatch(this.computed);
|
|
1013
|
+
this.computed.dispose();
|
|
993
1014
|
disposeOwner(this.owner);
|
|
994
1015
|
}
|
|
995
1016
|
};
|
|
@@ -1028,13 +1049,15 @@ function createSignal(value, options) {
|
|
|
1028
1049
|
},
|
|
1029
1050
|
enumerable: false
|
|
1030
1051
|
});
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1052
|
+
if (isObserved()) {
|
|
1053
|
+
reportReactiveNode({
|
|
1054
|
+
kind: "signal",
|
|
1055
|
+
node: state,
|
|
1056
|
+
handle: read,
|
|
1057
|
+
name: options?.name,
|
|
1058
|
+
set: write
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1038
1061
|
if (isObserved()) onCleanup(() => reportReactiveDispose(state));
|
|
1039
1062
|
return [read, write];
|
|
1040
1063
|
}
|
|
@@ -1058,8 +1081,11 @@ function createMemo(fn, value, options) {
|
|
|
1058
1081
|
const read = (() => c.get());
|
|
1059
1082
|
Object.defineProperty(read, $SIGNAL, { value: true, enumerable: true });
|
|
1060
1083
|
Object.defineProperty(read, $MEMO, { value: true, enumerable: true });
|
|
1061
|
-
reportReactiveNode({ kind: "memo", node: c, handle: read, name: options?.name });
|
|
1062
|
-
|
|
1084
|
+
if (isObserved()) reportReactiveNode({ kind: "memo", node: c, handle: read, name: options?.name });
|
|
1085
|
+
onCleanup(() => {
|
|
1086
|
+
c.dispose();
|
|
1087
|
+
if (isObserved()) reportReactiveDispose(c);
|
|
1088
|
+
});
|
|
1063
1089
|
return read;
|
|
1064
1090
|
}
|
|
1065
1091
|
function createEffect(fn, value, options) {
|
|
@@ -1116,6 +1142,20 @@ function on(deps, fn, options) {
|
|
|
1116
1142
|
}
|
|
1117
1143
|
|
|
1118
1144
|
// src/lib/signal/list.ts
|
|
1145
|
+
function lazyIndex(initial) {
|
|
1146
|
+
let current = initial;
|
|
1147
|
+
let state = null;
|
|
1148
|
+
return {
|
|
1149
|
+
index: () => {
|
|
1150
|
+
if (!state) state = createSignal(current, { name: "row index" });
|
|
1151
|
+
return state[0]();
|
|
1152
|
+
},
|
|
1153
|
+
set: (n) => {
|
|
1154
|
+
current = n;
|
|
1155
|
+
if (state) state[1](n);
|
|
1156
|
+
}
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1119
1159
|
function mapArray(list, mapFn, options) {
|
|
1120
1160
|
let items = [];
|
|
1121
1161
|
onCleanup(() => {
|
|
@@ -1145,9 +1185,9 @@ function mapArray(list, mapFn, options) {
|
|
|
1145
1185
|
let rendered, setIndex, dispose;
|
|
1146
1186
|
createRoot((d) => {
|
|
1147
1187
|
dispose = d;
|
|
1148
|
-
const
|
|
1149
|
-
setIndex =
|
|
1150
|
-
rendered = mapFn(value, index);
|
|
1188
|
+
const idx = lazyIndex(i);
|
|
1189
|
+
setIndex = idx.set;
|
|
1190
|
+
rendered = mapFn(value, idx.index);
|
|
1151
1191
|
});
|
|
1152
1192
|
const entry = { item: value, rendered, dispose, setIndex };
|
|
1153
1193
|
result.push(entry);
|
|
@@ -1187,21 +1227,19 @@ function keyArray(list, keyFn, mapFn, options) {
|
|
|
1187
1227
|
const reuse = prevByKey.get(key);
|
|
1188
1228
|
if (reuse && !usedKeys.has(key)) {
|
|
1189
1229
|
reuse.setIndex(i);
|
|
1230
|
+
reuse.setItem(next[i]);
|
|
1190
1231
|
resultEntries.push(reuse);
|
|
1191
1232
|
} else {
|
|
1192
|
-
let rendered, setIndex, dispose;
|
|
1233
|
+
let rendered, setIndex, setItem, dispose;
|
|
1193
1234
|
createRoot((d) => {
|
|
1194
1235
|
dispose = d;
|
|
1195
|
-
const
|
|
1196
|
-
setIndex =
|
|
1197
|
-
const item =
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
return v !== void 0 && v !== null ? v : prev;
|
|
1201
|
-
}, next[i]);
|
|
1202
|
-
rendered = mapFn(item, index);
|
|
1236
|
+
const idx = lazyIndex(i);
|
|
1237
|
+
setIndex = idx.set;
|
|
1238
|
+
const [item, writeItem] = createSignal(next[i]);
|
|
1239
|
+
setItem = (v) => writeItem(() => v);
|
|
1240
|
+
rendered = mapFn(item, idx.index);
|
|
1203
1241
|
});
|
|
1204
|
-
resultEntries.push({ rendered, dispose, setIndex });
|
|
1242
|
+
resultEntries.push({ rendered, dispose, setIndex, setItem });
|
|
1205
1243
|
}
|
|
1206
1244
|
resultKeys.push(key);
|
|
1207
1245
|
usedKeys.add(key);
|
|
@@ -1251,7 +1289,7 @@ function indexArray(list, mapFn, options) {
|
|
|
1251
1289
|
|
|
1252
1290
|
// src/lib/signal/graph/detect.ts
|
|
1253
1291
|
var __BROWSER_PROD__ = typeof window === "undefined" ? false : window.__FLUIXI_PROD__ === true;
|
|
1254
|
-
var __DEV__ = typeof process === "undefined" ? __BROWSER_PROD__ :
|
|
1292
|
+
var __DEV__ = typeof process === "undefined" ? __BROWSER_PROD__ : process.env.NODE_ENV !== "production";
|
|
1255
1293
|
var $SIGNAL2 = /* @__PURE__ */ Symbol.for("signal");
|
|
1256
1294
|
var $MEMO2 = /* @__PURE__ */ Symbol.for("memo");
|
|
1257
1295
|
var $RESOURCE = /* @__PURE__ */ Symbol.for("resource");
|
|
@@ -2070,12 +2108,14 @@ var Store = class {
|
|
|
2070
2108
|
OWNERS.set(initialState, { store: this, name: options.name ?? "store" });
|
|
2071
2109
|
ROOTS.set(initialState, initialState);
|
|
2072
2110
|
}
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2111
|
+
if (isObserved()) {
|
|
2112
|
+
reportReactiveNode({
|
|
2113
|
+
kind: "store",
|
|
2114
|
+
node: this,
|
|
2115
|
+
handle: () => this.root,
|
|
2116
|
+
name: options.name
|
|
2117
|
+
});
|
|
2118
|
+
}
|
|
2079
2119
|
}
|
|
2080
2120
|
get state() {
|
|
2081
2121
|
return box(this.root);
|
package/dist/lib/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @fluixi/reactive v1.0.0-alpha.
|
|
1
|
+
/*! @fluixi/reactive v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
2
|
"use strict";
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -159,7 +159,7 @@ __export(index_exports, {
|
|
|
159
159
|
module.exports = __toCommonJS(index_exports);
|
|
160
160
|
|
|
161
161
|
// src/version.generated.ts
|
|
162
|
-
var VERSION = "1.0.0-alpha.
|
|
162
|
+
var VERSION = "1.0.0-alpha.106";
|
|
163
163
|
|
|
164
164
|
// src/lib/predicates.ts
|
|
165
165
|
function isFunction(value) {
|
|
@@ -796,6 +796,7 @@ var Computed = class extends Source {
|
|
|
796
796
|
super();
|
|
797
797
|
this._threw = false;
|
|
798
798
|
this._initialized = false;
|
|
799
|
+
this._disposed = false;
|
|
799
800
|
this.state = DIRTY;
|
|
800
801
|
/** Nodes this computation read on its last run. Rebuilt on every run. */
|
|
801
802
|
this.sources = null;
|
|
@@ -811,8 +812,23 @@ var Computed = class extends Source {
|
|
|
811
812
|
if (this._threw) throw this._error;
|
|
812
813
|
return this._value;
|
|
813
814
|
}
|
|
815
|
+
/**
|
|
816
|
+
* Unlink from every source, for good. Without this, a source outlives the
|
|
817
|
+
* computation and keeps it (and everything its function captured) reachable
|
|
818
|
+
* through its observers set: a disposed list row stayed in memory that way.
|
|
819
|
+
* The last value stays readable; the node simply never updates again.
|
|
820
|
+
*/
|
|
821
|
+
dispose() {
|
|
822
|
+
if (this._disposed) return;
|
|
823
|
+
this._disposed = true;
|
|
824
|
+
if (this.sources) {
|
|
825
|
+
for (const s of this.sources) s.observers?.delete(this);
|
|
826
|
+
this.sources = null;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
814
829
|
/** Settle, if CHECK, verify sources; if DIRTY (or never run), recompute. */
|
|
815
830
|
updateIfNecessary() {
|
|
831
|
+
if (this._disposed) return;
|
|
816
832
|
if (this.state === CHECK) {
|
|
817
833
|
if (this.sources) {
|
|
818
834
|
for (const s of this.sources) {
|
|
@@ -856,7 +872,7 @@ var Computed = class extends Source {
|
|
|
856
872
|
reportReactiveRun(this);
|
|
857
873
|
if (changed) {
|
|
858
874
|
this.version++;
|
|
859
|
-
if (this.observers) for (const o of
|
|
875
|
+
if (this.observers) for (const o of this.observers) o.markDirty(DIRTY);
|
|
860
876
|
notifyWatchers(this);
|
|
861
877
|
}
|
|
862
878
|
}
|
|
@@ -870,7 +886,7 @@ var Computed = class extends Source {
|
|
|
870
886
|
const wasClean = this.state === CLEAN;
|
|
871
887
|
this.state = level;
|
|
872
888
|
if (wasClean) {
|
|
873
|
-
if (this.observers) for (const o of
|
|
889
|
+
if (this.observers) for (const o of this.observers) o.markDirty(CHECK);
|
|
874
890
|
notifyWatchers(this);
|
|
875
891
|
}
|
|
876
892
|
}
|
|
@@ -909,6 +925,10 @@ var Watcher = class {
|
|
|
909
925
|
this._pending.clear();
|
|
910
926
|
return out;
|
|
911
927
|
}
|
|
928
|
+
/** Drain pending without the array, for callers that only need it empty. */
|
|
929
|
+
clearPending() {
|
|
930
|
+
this._pending.clear();
|
|
931
|
+
}
|
|
912
932
|
/** @internal, a watched node became non-clean. Edge-triggered: notify once. */
|
|
913
933
|
_notify(node) {
|
|
914
934
|
if (!this._watched.has(node) || this._pending.has(node)) return;
|
|
@@ -1126,14 +1146,14 @@ var EffectNode = class {
|
|
|
1126
1146
|
if (typeof r === "function") (this.owner.cleanups ??= []).push(r);
|
|
1127
1147
|
});
|
|
1128
1148
|
});
|
|
1129
|
-
reportReactiveNode({ kind: "effect", node: this.computed, handle: this, internal: !report, ...name ? { name } : {} });
|
|
1149
|
+
if (isObserved()) reportReactiveNode({ kind: "effect", node: this.computed, handle: this, internal: !report, ...name ? { name } : {} });
|
|
1130
1150
|
this.watcher = new Watcher(() => enqueue(this));
|
|
1131
1151
|
this.run();
|
|
1132
1152
|
this.watcher.watch(this.computed);
|
|
1133
1153
|
}
|
|
1134
1154
|
run() {
|
|
1135
1155
|
if (this.disposed) return;
|
|
1136
|
-
this.watcher.
|
|
1156
|
+
this.watcher.clearPending();
|
|
1137
1157
|
try {
|
|
1138
1158
|
this.computed.get();
|
|
1139
1159
|
} catch (e) {
|
|
@@ -1150,6 +1170,7 @@ var EffectNode = class {
|
|
|
1150
1170
|
this.disposed = true;
|
|
1151
1171
|
reportReactiveDispose(this.computed);
|
|
1152
1172
|
this.watcher.unwatch(this.computed);
|
|
1173
|
+
this.computed.dispose();
|
|
1153
1174
|
disposeOwner(this.owner);
|
|
1154
1175
|
}
|
|
1155
1176
|
};
|
|
@@ -1188,13 +1209,15 @@ function createSignal(value, options) {
|
|
|
1188
1209
|
},
|
|
1189
1210
|
enumerable: false
|
|
1190
1211
|
});
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1212
|
+
if (isObserved()) {
|
|
1213
|
+
reportReactiveNode({
|
|
1214
|
+
kind: "signal",
|
|
1215
|
+
node: state,
|
|
1216
|
+
handle: read,
|
|
1217
|
+
name: options?.name,
|
|
1218
|
+
set: write
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1198
1221
|
if (isObserved()) onCleanup(() => reportReactiveDispose(state));
|
|
1199
1222
|
return [read, write];
|
|
1200
1223
|
}
|
|
@@ -1218,8 +1241,11 @@ function createMemo(fn, value, options) {
|
|
|
1218
1241
|
const read = (() => c.get());
|
|
1219
1242
|
Object.defineProperty(read, $SIGNAL, { value: true, enumerable: true });
|
|
1220
1243
|
Object.defineProperty(read, $MEMO, { value: true, enumerable: true });
|
|
1221
|
-
reportReactiveNode({ kind: "memo", node: c, handle: read, name: options?.name });
|
|
1222
|
-
|
|
1244
|
+
if (isObserved()) reportReactiveNode({ kind: "memo", node: c, handle: read, name: options?.name });
|
|
1245
|
+
onCleanup(() => {
|
|
1246
|
+
c.dispose();
|
|
1247
|
+
if (isObserved()) reportReactiveDispose(c);
|
|
1248
|
+
});
|
|
1223
1249
|
return read;
|
|
1224
1250
|
}
|
|
1225
1251
|
function createEffect(fn, value, options) {
|
|
@@ -1276,6 +1302,20 @@ function on(deps, fn, options) {
|
|
|
1276
1302
|
}
|
|
1277
1303
|
|
|
1278
1304
|
// src/lib/signal/list.ts
|
|
1305
|
+
function lazyIndex(initial) {
|
|
1306
|
+
let current = initial;
|
|
1307
|
+
let state = null;
|
|
1308
|
+
return {
|
|
1309
|
+
index: () => {
|
|
1310
|
+
if (!state) state = createSignal(current, { name: "row index" });
|
|
1311
|
+
return state[0]();
|
|
1312
|
+
},
|
|
1313
|
+
set: (n) => {
|
|
1314
|
+
current = n;
|
|
1315
|
+
if (state) state[1](n);
|
|
1316
|
+
}
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1279
1319
|
function mapArray(list, mapFn, options) {
|
|
1280
1320
|
let items = [];
|
|
1281
1321
|
onCleanup(() => {
|
|
@@ -1305,9 +1345,9 @@ function mapArray(list, mapFn, options) {
|
|
|
1305
1345
|
let rendered, setIndex, dispose;
|
|
1306
1346
|
createRoot((d) => {
|
|
1307
1347
|
dispose = d;
|
|
1308
|
-
const
|
|
1309
|
-
setIndex =
|
|
1310
|
-
rendered = mapFn(value, index);
|
|
1348
|
+
const idx = lazyIndex(i);
|
|
1349
|
+
setIndex = idx.set;
|
|
1350
|
+
rendered = mapFn(value, idx.index);
|
|
1311
1351
|
});
|
|
1312
1352
|
const entry = { item: value, rendered, dispose, setIndex };
|
|
1313
1353
|
result.push(entry);
|
|
@@ -1347,21 +1387,19 @@ function keyArray(list, keyFn, mapFn, options) {
|
|
|
1347
1387
|
const reuse = prevByKey.get(key);
|
|
1348
1388
|
if (reuse && !usedKeys.has(key)) {
|
|
1349
1389
|
reuse.setIndex(i);
|
|
1390
|
+
reuse.setItem(next[i]);
|
|
1350
1391
|
resultEntries.push(reuse);
|
|
1351
1392
|
} else {
|
|
1352
|
-
let rendered, setIndex, dispose;
|
|
1393
|
+
let rendered, setIndex, setItem, dispose;
|
|
1353
1394
|
createRoot((d) => {
|
|
1354
1395
|
dispose = d;
|
|
1355
|
-
const
|
|
1356
|
-
setIndex =
|
|
1357
|
-
const item =
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
return v !== void 0 && v !== null ? v : prev;
|
|
1361
|
-
}, next[i]);
|
|
1362
|
-
rendered = mapFn(item, index);
|
|
1396
|
+
const idx = lazyIndex(i);
|
|
1397
|
+
setIndex = idx.set;
|
|
1398
|
+
const [item, writeItem] = createSignal(next[i]);
|
|
1399
|
+
setItem = (v) => writeItem(() => v);
|
|
1400
|
+
rendered = mapFn(item, idx.index);
|
|
1363
1401
|
});
|
|
1364
|
-
resultEntries.push({ rendered, dispose, setIndex });
|
|
1402
|
+
resultEntries.push({ rendered, dispose, setIndex, setItem });
|
|
1365
1403
|
}
|
|
1366
1404
|
resultKeys.push(key);
|
|
1367
1405
|
usedKeys.add(key);
|
|
@@ -1411,7 +1449,7 @@ function indexArray(list, mapFn, options) {
|
|
|
1411
1449
|
|
|
1412
1450
|
// src/lib/signal/graph/detect.ts
|
|
1413
1451
|
var __BROWSER_PROD__ = typeof window === "undefined" ? false : window.__FLUIXI_PROD__ === true;
|
|
1414
|
-
var __DEV__ = typeof process === "undefined" ? __BROWSER_PROD__ :
|
|
1452
|
+
var __DEV__ = typeof process === "undefined" ? __BROWSER_PROD__ : process.env.NODE_ENV !== "production";
|
|
1415
1453
|
var $SIGNAL2 = /* @__PURE__ */ Symbol.for("signal");
|
|
1416
1454
|
var $MEMO2 = /* @__PURE__ */ Symbol.for("memo");
|
|
1417
1455
|
var $RESOURCE = /* @__PURE__ */ Symbol.for("resource");
|
|
@@ -2223,12 +2261,14 @@ var Store = class {
|
|
|
2223
2261
|
OWNERS.set(initialState, { store: this, name: options.name ?? "store" });
|
|
2224
2262
|
ROOTS.set(initialState, initialState);
|
|
2225
2263
|
}
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2264
|
+
if (isObserved()) {
|
|
2265
|
+
reportReactiveNode({
|
|
2266
|
+
kind: "store",
|
|
2267
|
+
node: this,
|
|
2268
|
+
handle: () => this.root,
|
|
2269
|
+
name: options.name
|
|
2270
|
+
});
|
|
2271
|
+
}
|
|
2232
2272
|
}
|
|
2233
2273
|
get state() {
|
|
2234
2274
|
return box(this.root);
|
package/dist/lib/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/*! @fluixi/reactive v1.0.0-alpha.
|
|
1
|
+
/*! @fluixi/reactive v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
2
|
|
|
3
3
|
// src/version.generated.ts
|
|
4
|
-
var VERSION = "1.0.0-alpha.
|
|
4
|
+
var VERSION = "1.0.0-alpha.106";
|
|
5
5
|
|
|
6
6
|
// src/lib/predicates.ts
|
|
7
7
|
function isFunction(value) {
|
|
@@ -638,6 +638,7 @@ var Computed = class extends Source {
|
|
|
638
638
|
super();
|
|
639
639
|
this._threw = false;
|
|
640
640
|
this._initialized = false;
|
|
641
|
+
this._disposed = false;
|
|
641
642
|
this.state = DIRTY;
|
|
642
643
|
/** Nodes this computation read on its last run. Rebuilt on every run. */
|
|
643
644
|
this.sources = null;
|
|
@@ -653,8 +654,23 @@ var Computed = class extends Source {
|
|
|
653
654
|
if (this._threw) throw this._error;
|
|
654
655
|
return this._value;
|
|
655
656
|
}
|
|
657
|
+
/**
|
|
658
|
+
* Unlink from every source, for good. Without this, a source outlives the
|
|
659
|
+
* computation and keeps it (and everything its function captured) reachable
|
|
660
|
+
* through its observers set: a disposed list row stayed in memory that way.
|
|
661
|
+
* The last value stays readable; the node simply never updates again.
|
|
662
|
+
*/
|
|
663
|
+
dispose() {
|
|
664
|
+
if (this._disposed) return;
|
|
665
|
+
this._disposed = true;
|
|
666
|
+
if (this.sources) {
|
|
667
|
+
for (const s of this.sources) s.observers?.delete(this);
|
|
668
|
+
this.sources = null;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
656
671
|
/** Settle, if CHECK, verify sources; if DIRTY (or never run), recompute. */
|
|
657
672
|
updateIfNecessary() {
|
|
673
|
+
if (this._disposed) return;
|
|
658
674
|
if (this.state === CHECK) {
|
|
659
675
|
if (this.sources) {
|
|
660
676
|
for (const s of this.sources) {
|
|
@@ -698,7 +714,7 @@ var Computed = class extends Source {
|
|
|
698
714
|
reportReactiveRun(this);
|
|
699
715
|
if (changed) {
|
|
700
716
|
this.version++;
|
|
701
|
-
if (this.observers) for (const o of
|
|
717
|
+
if (this.observers) for (const o of this.observers) o.markDirty(DIRTY);
|
|
702
718
|
notifyWatchers(this);
|
|
703
719
|
}
|
|
704
720
|
}
|
|
@@ -712,7 +728,7 @@ var Computed = class extends Source {
|
|
|
712
728
|
const wasClean = this.state === CLEAN;
|
|
713
729
|
this.state = level;
|
|
714
730
|
if (wasClean) {
|
|
715
|
-
if (this.observers) for (const o of
|
|
731
|
+
if (this.observers) for (const o of this.observers) o.markDirty(CHECK);
|
|
716
732
|
notifyWatchers(this);
|
|
717
733
|
}
|
|
718
734
|
}
|
|
@@ -751,6 +767,10 @@ var Watcher = class {
|
|
|
751
767
|
this._pending.clear();
|
|
752
768
|
return out;
|
|
753
769
|
}
|
|
770
|
+
/** Drain pending without the array, for callers that only need it empty. */
|
|
771
|
+
clearPending() {
|
|
772
|
+
this._pending.clear();
|
|
773
|
+
}
|
|
754
774
|
/** @internal, a watched node became non-clean. Edge-triggered: notify once. */
|
|
755
775
|
_notify(node) {
|
|
756
776
|
if (!this._watched.has(node) || this._pending.has(node)) return;
|
|
@@ -968,14 +988,14 @@ var EffectNode = class {
|
|
|
968
988
|
if (typeof r === "function") (this.owner.cleanups ??= []).push(r);
|
|
969
989
|
});
|
|
970
990
|
});
|
|
971
|
-
reportReactiveNode({ kind: "effect", node: this.computed, handle: this, internal: !report, ...name ? { name } : {} });
|
|
991
|
+
if (isObserved()) reportReactiveNode({ kind: "effect", node: this.computed, handle: this, internal: !report, ...name ? { name } : {} });
|
|
972
992
|
this.watcher = new Watcher(() => enqueue(this));
|
|
973
993
|
this.run();
|
|
974
994
|
this.watcher.watch(this.computed);
|
|
975
995
|
}
|
|
976
996
|
run() {
|
|
977
997
|
if (this.disposed) return;
|
|
978
|
-
this.watcher.
|
|
998
|
+
this.watcher.clearPending();
|
|
979
999
|
try {
|
|
980
1000
|
this.computed.get();
|
|
981
1001
|
} catch (e) {
|
|
@@ -992,6 +1012,7 @@ var EffectNode = class {
|
|
|
992
1012
|
this.disposed = true;
|
|
993
1013
|
reportReactiveDispose(this.computed);
|
|
994
1014
|
this.watcher.unwatch(this.computed);
|
|
1015
|
+
this.computed.dispose();
|
|
995
1016
|
disposeOwner(this.owner);
|
|
996
1017
|
}
|
|
997
1018
|
};
|
|
@@ -1030,13 +1051,15 @@ function createSignal(value, options) {
|
|
|
1030
1051
|
},
|
|
1031
1052
|
enumerable: false
|
|
1032
1053
|
});
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1054
|
+
if (isObserved()) {
|
|
1055
|
+
reportReactiveNode({
|
|
1056
|
+
kind: "signal",
|
|
1057
|
+
node: state,
|
|
1058
|
+
handle: read,
|
|
1059
|
+
name: options?.name,
|
|
1060
|
+
set: write
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1040
1063
|
if (isObserved()) onCleanup(() => reportReactiveDispose(state));
|
|
1041
1064
|
return [read, write];
|
|
1042
1065
|
}
|
|
@@ -1060,8 +1083,11 @@ function createMemo(fn, value, options) {
|
|
|
1060
1083
|
const read = (() => c.get());
|
|
1061
1084
|
Object.defineProperty(read, $SIGNAL, { value: true, enumerable: true });
|
|
1062
1085
|
Object.defineProperty(read, $MEMO, { value: true, enumerable: true });
|
|
1063
|
-
reportReactiveNode({ kind: "memo", node: c, handle: read, name: options?.name });
|
|
1064
|
-
|
|
1086
|
+
if (isObserved()) reportReactiveNode({ kind: "memo", node: c, handle: read, name: options?.name });
|
|
1087
|
+
onCleanup(() => {
|
|
1088
|
+
c.dispose();
|
|
1089
|
+
if (isObserved()) reportReactiveDispose(c);
|
|
1090
|
+
});
|
|
1065
1091
|
return read;
|
|
1066
1092
|
}
|
|
1067
1093
|
function createEffect(fn, value, options) {
|
|
@@ -1118,6 +1144,20 @@ function on(deps, fn, options) {
|
|
|
1118
1144
|
}
|
|
1119
1145
|
|
|
1120
1146
|
// src/lib/signal/list.ts
|
|
1147
|
+
function lazyIndex(initial) {
|
|
1148
|
+
let current = initial;
|
|
1149
|
+
let state = null;
|
|
1150
|
+
return {
|
|
1151
|
+
index: () => {
|
|
1152
|
+
if (!state) state = createSignal(current, { name: "row index" });
|
|
1153
|
+
return state[0]();
|
|
1154
|
+
},
|
|
1155
|
+
set: (n) => {
|
|
1156
|
+
current = n;
|
|
1157
|
+
if (state) state[1](n);
|
|
1158
|
+
}
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1121
1161
|
function mapArray(list, mapFn, options) {
|
|
1122
1162
|
let items = [];
|
|
1123
1163
|
onCleanup(() => {
|
|
@@ -1147,9 +1187,9 @@ function mapArray(list, mapFn, options) {
|
|
|
1147
1187
|
let rendered, setIndex, dispose;
|
|
1148
1188
|
createRoot((d) => {
|
|
1149
1189
|
dispose = d;
|
|
1150
|
-
const
|
|
1151
|
-
setIndex =
|
|
1152
|
-
rendered = mapFn(value, index);
|
|
1190
|
+
const idx = lazyIndex(i);
|
|
1191
|
+
setIndex = idx.set;
|
|
1192
|
+
rendered = mapFn(value, idx.index);
|
|
1153
1193
|
});
|
|
1154
1194
|
const entry = { item: value, rendered, dispose, setIndex };
|
|
1155
1195
|
result.push(entry);
|
|
@@ -1189,21 +1229,19 @@ function keyArray(list, keyFn, mapFn, options) {
|
|
|
1189
1229
|
const reuse = prevByKey.get(key);
|
|
1190
1230
|
if (reuse && !usedKeys.has(key)) {
|
|
1191
1231
|
reuse.setIndex(i);
|
|
1232
|
+
reuse.setItem(next[i]);
|
|
1192
1233
|
resultEntries.push(reuse);
|
|
1193
1234
|
} else {
|
|
1194
|
-
let rendered, setIndex, dispose;
|
|
1235
|
+
let rendered, setIndex, setItem, dispose;
|
|
1195
1236
|
createRoot((d) => {
|
|
1196
1237
|
dispose = d;
|
|
1197
|
-
const
|
|
1198
|
-
setIndex =
|
|
1199
|
-
const item =
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
return v !== void 0 && v !== null ? v : prev;
|
|
1203
|
-
}, next[i]);
|
|
1204
|
-
rendered = mapFn(item, index);
|
|
1238
|
+
const idx = lazyIndex(i);
|
|
1239
|
+
setIndex = idx.set;
|
|
1240
|
+
const [item, writeItem] = createSignal(next[i]);
|
|
1241
|
+
setItem = (v) => writeItem(() => v);
|
|
1242
|
+
rendered = mapFn(item, idx.index);
|
|
1205
1243
|
});
|
|
1206
|
-
resultEntries.push({ rendered, dispose, setIndex });
|
|
1244
|
+
resultEntries.push({ rendered, dispose, setIndex, setItem });
|
|
1207
1245
|
}
|
|
1208
1246
|
resultKeys.push(key);
|
|
1209
1247
|
usedKeys.add(key);
|
|
@@ -1253,7 +1291,7 @@ function indexArray(list, mapFn, options) {
|
|
|
1253
1291
|
|
|
1254
1292
|
// src/lib/signal/graph/detect.ts
|
|
1255
1293
|
var __BROWSER_PROD__ = typeof window === "undefined" ? false : window.__FLUIXI_PROD__ === true;
|
|
1256
|
-
var __DEV__ = typeof process === "undefined" ? __BROWSER_PROD__ :
|
|
1294
|
+
var __DEV__ = typeof process === "undefined" ? __BROWSER_PROD__ : process.env.NODE_ENV !== "production";
|
|
1257
1295
|
var $SIGNAL2 = /* @__PURE__ */ Symbol.for("signal");
|
|
1258
1296
|
var $MEMO2 = /* @__PURE__ */ Symbol.for("memo");
|
|
1259
1297
|
var $RESOURCE = /* @__PURE__ */ Symbol.for("resource");
|
|
@@ -2072,12 +2110,14 @@ var Store = class {
|
|
|
2072
2110
|
OWNERS.set(initialState, { store: this, name: options.name ?? "store" });
|
|
2073
2111
|
ROOTS.set(initialState, initialState);
|
|
2074
2112
|
}
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2113
|
+
if (isObserved()) {
|
|
2114
|
+
reportReactiveNode({
|
|
2115
|
+
kind: "store",
|
|
2116
|
+
node: this,
|
|
2117
|
+
handle: () => this.root,
|
|
2118
|
+
name: options.name
|
|
2119
|
+
});
|
|
2120
|
+
}
|
|
2081
2121
|
}
|
|
2082
2122
|
get state() {
|
|
2083
2123
|
return box(this.root);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @fluixi/reactive v1.0.0-alpha.
|
|
1
|
+
/*! @fluixi/reactive v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
2
|
"use strict";
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|