tutuca 0.13.2 → 0.14.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.
- package/dist/tutuca-cli.js +611 -458
- package/dist/tutuca-dev.ext.js +642 -486
- package/dist/tutuca-dev.js +653 -497
- package/dist/tutuca-dev.min.js +4 -4
- package/dist/tutuca-extra.ext.js +625 -451
- package/dist/tutuca-extra.js +632 -458
- package/dist/tutuca-extra.min.js +3 -3
- package/dist/tutuca.ext.js +625 -451
- package/dist/tutuca.js +632 -458
- package/dist/tutuca.min.js +3 -3
- package/package.json +1 -1
- package/skill/tutuca/SKILL.md +2 -2
- package/skill/tutuca/advanced.md +48 -17
- package/skill/tutuca/component-design.md +2 -2
- package/skill/tutuca/core.md +7 -1
- package/skill/tutuca/messages-and-intents.md +1 -1
- package/skill/tutuca/patterns/README.md +1 -1
- package/skill/tutuca/patterns/edit-through-a-dynamic-target.md +11 -6
- package/skill/tutuca/patterns/share-state-across-the-tree.md +18 -3
- package/skill/tutuca/semantics.md +43 -28
- package/skill/tutuca-source/tutuca.ext.js +625 -451
package/dist/tutuca-extra.js
CHANGED
|
@@ -293,7 +293,7 @@ function processResult(result, scope) {
|
|
|
293
293
|
}
|
|
294
294
|
return result !== NOTHING ? result : void 0;
|
|
295
295
|
}
|
|
296
|
-
function finalize(rootScope, value,
|
|
296
|
+
function finalize(rootScope, value, path2) {
|
|
297
297
|
if (isFrozen(value))
|
|
298
298
|
return value;
|
|
299
299
|
const useStrictIteration = rootScope.immer_.shouldUseStrictIteration();
|
|
@@ -301,7 +301,7 @@ function finalize(rootScope, value, path) {
|
|
|
301
301
|
if (!state) {
|
|
302
302
|
each(
|
|
303
303
|
value,
|
|
304
|
-
(key, childValue) => finalizeProperty(rootScope, state, value, key, childValue,
|
|
304
|
+
(key, childValue) => finalizeProperty(rootScope, state, value, key, childValue, path2),
|
|
305
305
|
useStrictIteration
|
|
306
306
|
);
|
|
307
307
|
return value;
|
|
@@ -331,16 +331,16 @@ function finalize(rootScope, value, path) {
|
|
|
331
331
|
result,
|
|
332
332
|
key,
|
|
333
333
|
childValue,
|
|
334
|
-
|
|
334
|
+
path2,
|
|
335
335
|
isSet2
|
|
336
336
|
),
|
|
337
337
|
useStrictIteration
|
|
338
338
|
);
|
|
339
339
|
maybeFreeze(rootScope, result, false);
|
|
340
|
-
if (
|
|
340
|
+
if (path2 && rootScope.patches_) {
|
|
341
341
|
getPlugin("Patches").generatePatches_(
|
|
342
342
|
state,
|
|
343
|
-
|
|
343
|
+
path2,
|
|
344
344
|
rootScope.patches_,
|
|
345
345
|
rootScope.inversePatches_
|
|
346
346
|
);
|
|
@@ -362,9 +362,9 @@ function finalizeProperty(rootScope, parentState, targetObject, prop, childValue
|
|
|
362
362
|
if (childValue === targetObject)
|
|
363
363
|
die(5);
|
|
364
364
|
if (isDraft(childValue)) {
|
|
365
|
-
const
|
|
365
|
+
const path2 = rootPath && parentState && parentState.type_ !== 3 && // Set objects are atomic since they have no keys.
|
|
366
366
|
!has(parentState.assigned_, prop) ? rootPath.concat(prop) : void 0;
|
|
367
|
-
const res = finalize(rootScope, childValue,
|
|
367
|
+
const res = finalize(rootScope, childValue, path2);
|
|
368
368
|
set(targetObject, prop, res);
|
|
369
369
|
if (isDraft(res)) {
|
|
370
370
|
rootScope.canAutoFreeze_ = false;
|
|
@@ -779,8 +779,11 @@ var Step = class {
|
|
|
779
779
|
}
|
|
780
780
|
setDraftValue(_root, _v) {
|
|
781
781
|
}
|
|
782
|
-
|
|
783
|
-
|
|
782
|
+
// Re-enter this step while rebuilding a stack. `renderPath` is the dispatch
|
|
783
|
+
// position AFTER this step: a rebuilt frame must carry the same render path
|
|
784
|
+
// the renderer had there, or the provides it publishes would be located wrong.
|
|
785
|
+
enterFrame(stack, next, renderPath) {
|
|
786
|
+
return stack.enter(next, {}, true, renderPath);
|
|
784
787
|
}
|
|
785
788
|
toAbstractPathStep() {
|
|
786
789
|
return this;
|
|
@@ -805,8 +808,8 @@ var BindStep = class _BindStep extends Step {
|
|
|
805
808
|
lookup(v, _dval) {
|
|
806
809
|
return v;
|
|
807
810
|
}
|
|
808
|
-
enterFrame(stack, next) {
|
|
809
|
-
return stack.enter(next, { ...this.binds }, false);
|
|
811
|
+
enterFrame(stack, next, renderPath) {
|
|
812
|
+
return stack.enter(next, { ...this.binds }, false, renderPath);
|
|
810
813
|
}
|
|
811
814
|
withIndex(i) {
|
|
812
815
|
return new _BindStep({ ...this.binds, key: i });
|
|
@@ -823,9 +826,9 @@ var ScopeBindStep = class _ScopeBindStep extends BindStep {
|
|
|
823
826
|
super(binds);
|
|
824
827
|
this.val = val;
|
|
825
828
|
}
|
|
826
|
-
enterFrame(stack, next) {
|
|
829
|
+
enterFrame(stack, next, renderPath) {
|
|
827
830
|
const dyn = this.val.evalAsHandler(stack)?.call(stack.it) ?? {};
|
|
828
|
-
return stack.enter(next, { ...this.binds, ...dyn }, false);
|
|
831
|
+
return stack.enter(next, { ...this.binds, ...dyn }, false, renderPath);
|
|
829
832
|
}
|
|
830
833
|
withIndex(i) {
|
|
831
834
|
return new _ScopeBindStep(this.val, { ...this.binds, key: i });
|
|
@@ -868,8 +871,8 @@ var SeqStep = class extends Step {
|
|
|
868
871
|
const seq = readKey(root, this.field, null);
|
|
869
872
|
if (seq != null) writeSeqKey(seq, this.key, v);
|
|
870
873
|
}
|
|
871
|
-
enterFrame(stack, next) {
|
|
872
|
-
return stack.enter(next, { key: this.key }, true);
|
|
874
|
+
enterFrame(stack, next, renderPath) {
|
|
875
|
+
return stack.enter(next, { key: this.key }, true, renderPath);
|
|
873
876
|
}
|
|
874
877
|
toKey() {
|
|
875
878
|
return { field: this.field, key: this.key };
|
|
@@ -915,60 +918,52 @@ var EachBindStep = class extends Step {
|
|
|
915
918
|
}
|
|
916
919
|
// Replay the renderer's per-item binds (key, value + any @enrich-with binds)
|
|
917
920
|
// so a rebuilt stack matches the one @each rendered with.
|
|
918
|
-
enterFrame(stack, next) {
|
|
919
|
-
return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false);
|
|
921
|
+
enterFrame(stack, next, renderPath) {
|
|
922
|
+
return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false, renderPath);
|
|
920
923
|
}
|
|
921
924
|
toAbstractPathStep() {
|
|
922
925
|
return null;
|
|
923
926
|
}
|
|
924
927
|
};
|
|
925
928
|
var EachRenderItStep = class extends SeqStep {
|
|
926
|
-
enterFrame(stack, next) {
|
|
927
|
-
return stack.enter(next, { key: this.key, value: next }, false).enter(next, {}, true);
|
|
929
|
+
enterFrame(stack, next, renderPath) {
|
|
930
|
+
return stack.enter(next, { key: this.key, value: next }, false, renderPath).enter(next, {}, true, renderPath);
|
|
928
931
|
}
|
|
929
932
|
toAbstractPathStep() {
|
|
930
933
|
return new SeqStep(this.field, this.key);
|
|
931
934
|
}
|
|
932
935
|
};
|
|
933
|
-
function
|
|
934
|
-
|
|
936
|
+
function stepToJson(step) {
|
|
937
|
+
if (step instanceof SeqStep) return { f: step.field, k: step.key };
|
|
938
|
+
if (step instanceof FieldStep) return { f: step.field };
|
|
939
|
+
if (step instanceof SeqAccessStep) return { f: step.seqField, a: step.keyField };
|
|
940
|
+
return null;
|
|
935
941
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
warnRawDynStep("lookup", this);
|
|
949
|
-
return dval;
|
|
950
|
-
}
|
|
951
|
-
enterFrame(stack, _next) {
|
|
952
|
-
warnRawDynStep("enterFrame", this);
|
|
953
|
-
return stack;
|
|
954
|
-
}
|
|
955
|
-
};
|
|
956
|
-
var DynEachStep = class extends DynStep {
|
|
957
|
-
constructor(producerCompId, producerSteps, key) {
|
|
958
|
-
super(producerCompId, producerSteps);
|
|
959
|
-
this.key = key;
|
|
960
|
-
}
|
|
961
|
-
teleportSteps() {
|
|
962
|
-
const { producerSteps, key } = this;
|
|
963
|
-
if (producerSteps.length === 0) return producerSteps;
|
|
964
|
-
const last = producerSteps[producerSteps.length - 1];
|
|
965
|
-
if (!(last instanceof FieldStep)) {
|
|
966
|
-
console.warn("DynEachStep: seq-access dynamic cannot be iterated", this);
|
|
967
|
-
return producerSteps;
|
|
968
|
-
}
|
|
969
|
-
return producerSteps.slice(0, -1).concat(new SeqStep(last.field, key));
|
|
942
|
+
function stepFromJson(j) {
|
|
943
|
+
if (j == null || typeof j.f !== "string") return null;
|
|
944
|
+
if (j.k !== void 0) return new SeqStep(j.f, j.k);
|
|
945
|
+
if (j.a !== void 0) return new SeqAccessStep(j.f, j.a);
|
|
946
|
+
return new FieldStep(j.f);
|
|
947
|
+
}
|
|
948
|
+
function pathToJson(path2) {
|
|
949
|
+
const out = [];
|
|
950
|
+
for (const step of path2.steps) {
|
|
951
|
+
const j = stepToJson(step);
|
|
952
|
+
if (j === null) return null;
|
|
953
|
+
out.push(j);
|
|
970
954
|
}
|
|
971
|
-
|
|
955
|
+
return out;
|
|
956
|
+
}
|
|
957
|
+
function pathFromJson(j) {
|
|
958
|
+
if (!Array.isArray(j)) return null;
|
|
959
|
+
const steps = [];
|
|
960
|
+
for (const item of j) {
|
|
961
|
+
const step = stepFromJson(item);
|
|
962
|
+
if (step === null) return null;
|
|
963
|
+
steps.push(step);
|
|
964
|
+
}
|
|
965
|
+
return new Path(steps);
|
|
966
|
+
}
|
|
972
967
|
var Path = class _Path {
|
|
973
968
|
constructor(steps = []) {
|
|
974
969
|
this.steps = steps;
|
|
@@ -979,40 +974,13 @@ var Path = class _Path {
|
|
|
979
974
|
popStep() {
|
|
980
975
|
return new _Path(this.steps.slice(0, -1));
|
|
981
976
|
}
|
|
982
|
-
//
|
|
983
|
-
//
|
|
977
|
+
// Frame-only steps removed, one step per crossed component: `popStep` over the
|
|
978
|
+
// result bubbles through every component.
|
|
984
979
|
compact() {
|
|
985
980
|
const out = [];
|
|
986
981
|
for (const step of this.steps) {
|
|
987
982
|
const s = step.toAbstractPathStep();
|
|
988
|
-
if (s !== null)
|
|
989
|
-
if (s !== step) s._originCid = step._originCid;
|
|
990
|
-
out.push(s);
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
return new _Path(out);
|
|
994
|
-
}
|
|
995
|
-
// The abstract path used to apply a transaction: every DynStep is teleported —
|
|
996
|
-
// the steps interior to its producer..consumer span are dropped and the
|
|
997
|
-
// producer's own path spliced in — so a mutation lands on the data's real
|
|
998
|
-
// location. A path with no DynStep is returned unchanged.
|
|
999
|
-
toTransactionPath() {
|
|
1000
|
-
let hasDyn = false;
|
|
1001
|
-
for (const step of this.steps)
|
|
1002
|
-
if (step instanceof DynStep) {
|
|
1003
|
-
hasDyn = true;
|
|
1004
|
-
break;
|
|
1005
|
-
}
|
|
1006
|
-
if (!hasDyn) return this;
|
|
1007
|
-
const out = [];
|
|
1008
|
-
for (const step of this.steps) {
|
|
1009
|
-
if (step instanceof DynStep) {
|
|
1010
|
-
while (out.length > 0 && step.interiorCids.has(out[out.length - 1]._originCid)) out.pop();
|
|
1011
|
-
for (const ts of step.teleportSteps()) {
|
|
1012
|
-
ts._originCid = step.producerCompId;
|
|
1013
|
-
out.push(ts);
|
|
1014
|
-
}
|
|
1015
|
-
} else out.push(step);
|
|
983
|
+
if (s !== null) out.push(s);
|
|
1016
984
|
}
|
|
1017
985
|
return new _Path(out);
|
|
1018
986
|
}
|
|
@@ -1020,7 +988,6 @@ var Path = class _Path {
|
|
|
1020
988
|
// key as it is *now* so a later lookup/setValue lands on the same item even if the
|
|
1021
989
|
// keyField changed meanwhile (e.g. the selected tab moved while an intent was in
|
|
1022
990
|
// flight). Returns a new Path with those steps replaced; `this` if nothing pinned.
|
|
1023
|
-
// Must be called on a transaction path (no DynSteps — call toTransactionPath first).
|
|
1024
991
|
pinKeys(root) {
|
|
1025
992
|
let curVal = root;
|
|
1026
993
|
let out = null;
|
|
@@ -1043,8 +1010,8 @@ var Path = class _Path {
|
|
|
1043
1010
|
}
|
|
1044
1011
|
// The values entered along the path, root→leaf (root included): index 0 is `root`,
|
|
1045
1012
|
// the last entry is the leaf this path resolves to. Stops early at the first
|
|
1046
|
-
// unresolvable step.
|
|
1047
|
-
//
|
|
1013
|
+
// unresolvable step. Used to walk the component instances on a dispatch path
|
|
1014
|
+
// (filter via Components.getCompFor).
|
|
1048
1015
|
resolveChain(root) {
|
|
1049
1016
|
const out = [root];
|
|
1050
1017
|
let curVal = root;
|
|
@@ -1058,7 +1025,7 @@ var Path = class _Path {
|
|
|
1058
1025
|
// A flat `[{ field, key? }]` list of the addressing steps, skipping frame-only
|
|
1059
1026
|
// steps (binds). Generic path introspection so tooling (e.g. the storybook
|
|
1060
1027
|
// activity log) can identify which subtree a transaction touched without
|
|
1061
|
-
// depending on Step internals.
|
|
1028
|
+
// depending on Step internals.
|
|
1062
1029
|
toKeys() {
|
|
1063
1030
|
const out = [];
|
|
1064
1031
|
for (const step of this.steps) {
|
|
@@ -1079,62 +1046,147 @@ var Path = class _Path {
|
|
|
1079
1046
|
});
|
|
1080
1047
|
}
|
|
1081
1048
|
buildStack(stack) {
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1049
|
+
return walkItems(stack, this.steps, stack.renderPath ?? new DispatchPath(), this)?.[0] ?? null;
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
function walkItems(stack, items, renderPath, path2) {
|
|
1053
|
+
let prev = stack.it;
|
|
1054
|
+
for (const step of items) {
|
|
1055
|
+
const next = step.lookup(prev, NONE);
|
|
1056
|
+
if (next === NONE) {
|
|
1057
|
+
console.warn("bad PathItem", { root: stack.it, step, path: path2 });
|
|
1058
|
+
return null;
|
|
1059
|
+
}
|
|
1060
|
+
renderPath = renderPath.pushItem(step);
|
|
1061
|
+
stack = step.enterFrame(stack, next, renderPath);
|
|
1062
|
+
prev = next;
|
|
1063
|
+
}
|
|
1064
|
+
return [stack, renderPath];
|
|
1065
|
+
}
|
|
1066
|
+
var EMPTY_PATH = new Path([]);
|
|
1067
|
+
var DispatchPath = class _DispatchPath {
|
|
1068
|
+
constructor(frames = [{ base: EMPTY_PATH, items: [] }]) {
|
|
1069
|
+
this.frames = frames;
|
|
1070
|
+
}
|
|
1071
|
+
// Plain addressing steps in one frame based at the root: what a caller means
|
|
1072
|
+
// by "this position" when it has no continuation of its own.
|
|
1073
|
+
static ofSteps(steps) {
|
|
1074
|
+
return new _DispatchPath([{ base: EMPTY_PATH, items: steps.slice() }]);
|
|
1075
|
+
}
|
|
1076
|
+
get top() {
|
|
1077
|
+
return this.frames[this.frames.length - 1];
|
|
1078
|
+
}
|
|
1079
|
+
_withTopItems(items) {
|
|
1080
|
+
const frames = this.frames.slice();
|
|
1081
|
+
frames[frames.length - 1] = { base: this.top.base, items };
|
|
1082
|
+
return new _DispatchPath(frames);
|
|
1083
|
+
}
|
|
1084
|
+
concat(steps) {
|
|
1085
|
+
if (this.frames.length === 0) return _DispatchPath.ofSteps(steps);
|
|
1086
|
+
return this._withTopItems(this.top.items.concat(steps));
|
|
1087
|
+
}
|
|
1088
|
+
pushItem(step) {
|
|
1089
|
+
return this.concat([step]);
|
|
1090
|
+
}
|
|
1091
|
+
pushFrame(base) {
|
|
1092
|
+
return new _DispatchPath(this.frames.concat({ base, items: [] }));
|
|
1093
|
+
}
|
|
1094
|
+
// Whether bubbling has anywhere left to go: another step in this frame, or a
|
|
1095
|
+
// visual caller underneath it.
|
|
1096
|
+
canPop() {
|
|
1097
|
+
const n = this.frames.length;
|
|
1098
|
+
return n > 1 || n === 1 && this.frames[0].items.length > 0;
|
|
1099
|
+
}
|
|
1100
|
+
isRoot() {
|
|
1101
|
+
return this.toTransactionPath().steps.length === 0;
|
|
1102
|
+
}
|
|
1103
|
+
// One component closer to the root. At the top of a frame that is popping back
|
|
1104
|
+
// to the visual caller, not to the producer's own parent — the caller is where
|
|
1105
|
+
// the `*name` was written, and where an unhandled message should keep going.
|
|
1106
|
+
popStep() {
|
|
1107
|
+
const n = this.frames.length;
|
|
1108
|
+
if (n === 0) return this;
|
|
1109
|
+
const top = this.frames[n - 1];
|
|
1110
|
+
if (top.items.length > 0) return this._withTopItems(top.items.slice(0, -1));
|
|
1111
|
+
if (n > 1) return new _DispatchPath(this.frames.slice(0, -1));
|
|
1112
|
+
return this;
|
|
1113
|
+
}
|
|
1114
|
+
// Drop frame-only steps inside every frame independently; a frame's base is
|
|
1115
|
+
// already addressing-only.
|
|
1116
|
+
compact() {
|
|
1117
|
+
return new _DispatchPath(
|
|
1118
|
+
this.frames.map(({ base, items }) => ({ base, items: new Path(items).compact().steps }))
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1121
|
+
// A stable string for the ADDRESS this path denotes, for the render cache. The
|
|
1122
|
+
// same immutable value can sit at two places in the tree, and a subtree rendered
|
|
1123
|
+
// at one of them bakes that address in — the provides it publishes are located
|
|
1124
|
+
// there. Frame-only steps address nothing, so they are compacted out: two sites
|
|
1125
|
+
// that differ only in binds do render the same subtree.
|
|
1126
|
+
get addressKey() {
|
|
1127
|
+
this._addressKey ??= renderPathText(this.toTransactionPath().compact());
|
|
1128
|
+
return this._addressKey;
|
|
1129
|
+
}
|
|
1130
|
+
// The active transaction address: the top frame's absolute base followed by
|
|
1131
|
+
// its ordinary descendant steps. This is where a mutation lands.
|
|
1132
|
+
toTransactionPath() {
|
|
1133
|
+
const top = this.top;
|
|
1134
|
+
return top === void 0 ? EMPTY_PATH : top.base.concat(top.items);
|
|
1135
|
+
}
|
|
1136
|
+
// Rebuild the render stack this path was dispatched from. A frame with a base
|
|
1137
|
+
// re-enters at that absolute value first — replaying the resume a `*name`
|
|
1138
|
+
// render performed — and then walks its ordinary items.
|
|
1139
|
+
buildStack(stack) {
|
|
1140
|
+
let renderPath = new _DispatchPath();
|
|
1141
|
+
for (let i = 0; i < this.frames.length; i++) {
|
|
1142
|
+
const { base, items } = this.frames[i];
|
|
1143
|
+
if (i > 0 || base.steps.length > 0) {
|
|
1144
|
+
const baseValue = base.lookup(stack.root, NONE);
|
|
1145
|
+
if (baseValue === NONE) {
|
|
1146
|
+
console.warn("bad frame base", { base, path: this });
|
|
1147
|
+
return null;
|
|
1148
|
+
}
|
|
1149
|
+
renderPath = renderPath.pushFrame(base);
|
|
1150
|
+
stack = stack.enter(baseValue, {}, true, renderPath);
|
|
1088
1151
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1152
|
+
const walked = walkItems(stack, items, renderPath, this);
|
|
1153
|
+
if (walked === null) return null;
|
|
1154
|
+
[stack, renderPath] = walked;
|
|
1091
1155
|
}
|
|
1092
1156
|
return stack;
|
|
1093
1157
|
}
|
|
1094
1158
|
static fromNodeAndEventName(node, eventName, rootNode, maxDepth, comps, stopOnNoEvent = true) {
|
|
1095
|
-
const
|
|
1096
|
-
const pendingDyns = [];
|
|
1159
|
+
const parts = [];
|
|
1097
1160
|
const bubbles = BUBBLING_EVENTS.has(eventName);
|
|
1098
1161
|
let depth = 0;
|
|
1099
1162
|
let eventIds = [];
|
|
1100
1163
|
let handlers = null;
|
|
1101
|
-
let
|
|
1164
|
+
let nodeRefs = [];
|
|
1102
1165
|
let isLeafComponent = true;
|
|
1103
1166
|
const crossComponent = (cidNum, vid) => {
|
|
1104
1167
|
const comp = comps.getComponentForId(cidNum);
|
|
1105
|
-
let
|
|
1168
|
+
let pushPart = true;
|
|
1106
1169
|
if (handlers === null && (isLeafComponent || bubbles)) {
|
|
1107
1170
|
handlers = findHandlers(comp, eventIds, vid, eventName);
|
|
1108
1171
|
if (handlers === null) {
|
|
1109
1172
|
if (isLeafComponent && stopOnNoEvent && !bubbles) return false;
|
|
1110
1173
|
} else if (!isLeafComponent) {
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
pushStep = false;
|
|
1174
|
+
parts.length = 0;
|
|
1175
|
+
pushPart = false;
|
|
1114
1176
|
}
|
|
1115
1177
|
}
|
|
1116
1178
|
isLeafComponent = false;
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
if (step) {
|
|
1121
|
-
step._originCid = cidNum;
|
|
1122
|
-
pathSteps.push(step);
|
|
1123
|
-
if (step instanceof DynStep) {
|
|
1124
|
-
step.interiorCids.add(cidNum);
|
|
1125
|
-
pendingDyns.push(step);
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1179
|
+
if (pushPart) {
|
|
1180
|
+
const part = resolvePathPart(comp, nodeRefs, vid);
|
|
1181
|
+
if (part) parts.push(part);
|
|
1128
1182
|
}
|
|
1129
|
-
for (let i = pendingDyns.length - 1; i >= 0; i--)
|
|
1130
|
-
if (pendingDyns[i].producerCompId === cidNum) pendingDyns.splice(i, 1);
|
|
1131
1183
|
eventIds = [];
|
|
1132
|
-
|
|
1184
|
+
nodeRefs = [];
|
|
1133
1185
|
return true;
|
|
1134
1186
|
};
|
|
1135
1187
|
while (node && node !== rootNode && depth < maxDepth) {
|
|
1136
1188
|
if (node?.dataset) {
|
|
1137
|
-
const { eid, cid, vid } = node.dataset;
|
|
1189
|
+
const { eid, cid, vid, rp } = node.dataset;
|
|
1138
1190
|
if (eid !== void 0) eventIds.push(eid);
|
|
1139
1191
|
const metas = metaChain(node.previousSibling);
|
|
1140
1192
|
let sawComp = false;
|
|
@@ -1142,21 +1194,47 @@ var Path = class _Path {
|
|
|
1142
1194
|
if (m.$ === "Comp") {
|
|
1143
1195
|
sawComp = true;
|
|
1144
1196
|
if (!crossComponent(m.cid, m.vid)) return NO_EVENT_INFO;
|
|
1145
|
-
|
|
1197
|
+
nodeRefs.push({ nid: m.nid, base: pathFromJson(m.base) });
|
|
1146
1198
|
} else {
|
|
1147
|
-
|
|
1199
|
+
nodeRefs.push({ nid: m.nid, si: m.si, sk: m.sk });
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
if (!sawComp && cid !== void 0) {
|
|
1203
|
+
if (!crossComponent(+cid, vid)) return NO_EVENT_INFO;
|
|
1204
|
+
if (rp !== void 0) {
|
|
1205
|
+
const base = parseRenderPath(rp);
|
|
1206
|
+
if (base !== null) nodeRefs.push({ base });
|
|
1148
1207
|
}
|
|
1149
1208
|
}
|
|
1150
|
-
if (!sawComp && cid !== void 0 && !crossComponent(+cid, vid)) return NO_EVENT_INFO;
|
|
1151
1209
|
}
|
|
1152
1210
|
depth += 1;
|
|
1153
1211
|
node = node.parentNode;
|
|
1154
1212
|
}
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1213
|
+
parts.reverse();
|
|
1214
|
+
let path2 = new _DispatchPath();
|
|
1215
|
+
for (const part of parts)
|
|
1216
|
+
path2 = part.base !== void 0 ? path2.pushFrame(part.base) : path2.pushItem(part.step);
|
|
1217
|
+
return [path2, handlers];
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
function keyedPath(path2, key) {
|
|
1221
|
+
const steps = path2.steps;
|
|
1222
|
+
const last = steps[steps.length - 1];
|
|
1223
|
+
if (last instanceof SeqStep || last instanceof FieldStep)
|
|
1224
|
+
return new Path(steps.slice(0, -1).concat(new SeqStep(last.field, key)));
|
|
1225
|
+
return null;
|
|
1226
|
+
}
|
|
1227
|
+
function renderPathText(path2) {
|
|
1228
|
+
return JSON.stringify(pathToJson(path2));
|
|
1229
|
+
}
|
|
1230
|
+
function parseRenderPath(text) {
|
|
1231
|
+
try {
|
|
1232
|
+
return pathFromJson(JSON.parse(text));
|
|
1233
|
+
} catch (err) {
|
|
1234
|
+
console.warn("bad render path", err, text);
|
|
1235
|
+
return null;
|
|
1158
1236
|
}
|
|
1159
|
-
}
|
|
1237
|
+
}
|
|
1160
1238
|
function metaChain(n) {
|
|
1161
1239
|
const out = [];
|
|
1162
1240
|
while (n?.nodeType === 8 && n.textContent[0] === "§") {
|
|
@@ -1209,20 +1287,27 @@ var StepCtx = class _StepCtx {
|
|
|
1209
1287
|
return pi;
|
|
1210
1288
|
}
|
|
1211
1289
|
};
|
|
1212
|
-
function
|
|
1213
|
-
for (let i = 0; i <
|
|
1214
|
-
const
|
|
1215
|
-
|
|
1216
|
-
if (
|
|
1290
|
+
function resolvePathPart(comp, nodeRefs, vid) {
|
|
1291
|
+
for (let i = 0; i < nodeRefs.length; i++) {
|
|
1292
|
+
const ref = nodeRefs[i];
|
|
1293
|
+
if (ref.base != null) return { base: ref.base };
|
|
1294
|
+
if (ref.nid === void 0 || ref.nid === null) continue;
|
|
1295
|
+
const ctx = new StepCtx(comp, nodeRefs, i, vid);
|
|
1296
|
+
const step = ctx.resolveNode()?.toPathStep(ctx) ?? null;
|
|
1297
|
+
if (step !== null) return { step };
|
|
1217
1298
|
}
|
|
1218
1299
|
return null;
|
|
1219
1300
|
}
|
|
1220
1301
|
var NO_EVENT_INFO = [null, null];
|
|
1221
1302
|
var BUBBLING_EVENTS = /* @__PURE__ */ new Set(["drop"]);
|
|
1303
|
+
var path = () => new PathBuilder();
|
|
1222
1304
|
var PathBuilder = class {
|
|
1223
1305
|
constructor() {
|
|
1224
1306
|
this.pathChanges = [];
|
|
1225
1307
|
}
|
|
1308
|
+
toPath() {
|
|
1309
|
+
return new Path(this.pathChanges);
|
|
1310
|
+
}
|
|
1226
1311
|
add(pathChange) {
|
|
1227
1312
|
this.pathChanges.push(pathChange);
|
|
1228
1313
|
return this;
|
|
@@ -1359,31 +1444,14 @@ function parseBool(s, px) {
|
|
|
1359
1444
|
const val = parseToken(tokens[0], px);
|
|
1360
1445
|
return val !== null && kindOf(val) & G_BOOL ? val : null;
|
|
1361
1446
|
}
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
}
|
|
1371
|
-
function parseField(s, px) {
|
|
1372
|
-
return _parseSingle(s, px, G_FIELD);
|
|
1373
|
-
}
|
|
1374
|
-
function parseProvide(s, px) {
|
|
1375
|
-
return _parseSingle(s, px, G_PROVIDE);
|
|
1376
|
-
}
|
|
1377
|
-
function parseMacroAttr(s, px) {
|
|
1378
|
-
return _parseSingle(s, px, G_ALL);
|
|
1379
|
-
}
|
|
1380
|
-
function parseReceiveHandler(s, px) {
|
|
1381
|
-
return _parseHandler(s, px, "receive", true, true, false);
|
|
1382
|
-
}
|
|
1383
|
-
function parseAlterHandler(s, px) {
|
|
1384
|
-
const r = _parseHandler(s, px, "alter", false, false, true);
|
|
1385
|
-
return r === null ? null : r.handlerVal;
|
|
1386
|
-
}
|
|
1447
|
+
var parseText = (s, px) => _parseSingle(s, px, G_TEXT);
|
|
1448
|
+
var parseComponent = (s, px) => _parseSingle(s, px, G_COMPONENT);
|
|
1449
|
+
var parseSequence = (s, px) => _parseSingle(s, px, G_SEQUENCE);
|
|
1450
|
+
var parseField = (s, px) => _parseSingle(s, px, G_FIELD);
|
|
1451
|
+
var parseProvide = (s, px) => _parseSingle(s, px, G_PROVIDE);
|
|
1452
|
+
var parseMacroAttr = (s, px) => _parseSingle(s, px, G_ALL);
|
|
1453
|
+
var parseReceiveHandler = (s, px) => _parseHandler(s, px, "receive", true, true, false);
|
|
1454
|
+
var parseAlterHandler = (s, px) => _parseHandler(s, px, "alter", false, false, true)?.handlerVal ?? null;
|
|
1387
1455
|
function _parseHandler(s, px, namespace, allowArgs, report, allowMethod) {
|
|
1388
1456
|
const tokens = tokenizeValue(s.trim());
|
|
1389
1457
|
const headTok = tokens[0] ?? "";
|
|
@@ -2072,19 +2140,9 @@ function childOpts(vnode, ns, opts) {
|
|
|
2072
2140
|
const target = ns === SVG_NS && isForeignObject(vnode.tag) ? null : ns;
|
|
2073
2141
|
return target === (opts.namespace ?? null) ? opts : { ...opts, namespace: target };
|
|
2074
2142
|
}
|
|
2075
|
-
var NEVER_ASSIGN =
|
|
2076
|
-
"width"
|
|
2077
|
-
|
|
2078
|
-
"href",
|
|
2079
|
-
"list",
|
|
2080
|
-
"form",
|
|
2081
|
-
"tabIndex",
|
|
2082
|
-
"download",
|
|
2083
|
-
"rowSpan",
|
|
2084
|
-
"colSpan",
|
|
2085
|
-
"role",
|
|
2086
|
-
"popover"
|
|
2087
|
-
]);
|
|
2143
|
+
var NEVER_ASSIGN = new Set(
|
|
2144
|
+
"width height href list form tabIndex download rowSpan colSpan role popover".split(" ")
|
|
2145
|
+
);
|
|
2088
2146
|
var PROP_ATTR_NAME = { className: "class", htmlFor: "for" };
|
|
2089
2147
|
function applyProperties(node, props) {
|
|
2090
2148
|
const namespaced = isNamespaced(node);
|
|
@@ -2363,6 +2421,10 @@ function morphChildren(parentDom, oldChilds, newChilds, opts) {
|
|
|
2363
2421
|
if (!used[i] && domNodes[i].parentNode === parentDom) parentDom.removeChild(domNodes[i]);
|
|
2364
2422
|
}
|
|
2365
2423
|
function render(vnode, container, options, prev) {
|
|
2424
|
+
if (vnode == null) {
|
|
2425
|
+
container.replaceChildren();
|
|
2426
|
+
return { vnode: null, dom: null };
|
|
2427
|
+
}
|
|
2366
2428
|
const isFragment = vnode instanceof VFragment;
|
|
2367
2429
|
if (prev && prev.vnode instanceof VFragment === isFragment) {
|
|
2368
2430
|
const oldDom = isFragment ? container : prev.dom;
|
|
@@ -2402,13 +2464,16 @@ function h(tagName, properties, children, namespace) {
|
|
|
2402
2464
|
}
|
|
2403
2465
|
|
|
2404
2466
|
// src/anode.js
|
|
2405
|
-
function
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2467
|
+
function renderTarget(val, stack) {
|
|
2468
|
+
if (val instanceof DynVal) {
|
|
2469
|
+
const loc = stack.lookupDynamicLocated(val.name);
|
|
2470
|
+
if (loc?.path == null) return [loc?.value ?? null, stack.renderPath, null];
|
|
2471
|
+
return [loc.value, stack.renderPath.pushFrame(loc.path), loc.path];
|
|
2472
|
+
}
|
|
2473
|
+
const step = val.toPathItem?.() ?? null;
|
|
2474
|
+
if (step === null) return [val.eval(stack), stack.renderPath, null];
|
|
2475
|
+
const path2 = stack.renderPath.pushItem(step);
|
|
2476
|
+
return [val.eval(stack), path2, stack.pendingFrame ? path2.toTransactionPath() : null];
|
|
2412
2477
|
}
|
|
2413
2478
|
var BaseNode = class {
|
|
2414
2479
|
render(_stack, _rx) {
|
|
@@ -2730,33 +2795,31 @@ var RenderViewId = class extends ANode {
|
|
|
2730
2795
|
setDataAttr(_key, _val) {
|
|
2731
2796
|
}
|
|
2732
2797
|
};
|
|
2733
|
-
function dynRenderStep(comp, name, key) {
|
|
2734
|
-
const p = resolveDynProducer(comp, name);
|
|
2735
|
-
if (!p) return null;
|
|
2736
|
-
return key === void 0 ? new DynStep(p.producerCompId, p.producerSteps) : new DynEachStep(p.producerCompId, p.producerSteps, key);
|
|
2737
|
-
}
|
|
2738
2798
|
var RenderNode = class extends RenderViewId {
|
|
2739
2799
|
render(stack, rx) {
|
|
2740
|
-
const
|
|
2741
|
-
|
|
2800
|
+
const [value, renderPath, base] = renderTarget(this.val, stack);
|
|
2801
|
+
const newStack = stack.enter(value, {}, true, renderPath, false);
|
|
2802
|
+
return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
|
|
2742
2803
|
}
|
|
2804
|
+
// A `*name` target contributes no step: the site recorded the absolute base it
|
|
2805
|
+
// resumed at, and event reconstruction turns that into a continuation frame.
|
|
2743
2806
|
toPathStep(ctx) {
|
|
2744
|
-
if (this.val instanceof DynVal) return
|
|
2807
|
+
if (this.val instanceof DynVal) return null;
|
|
2745
2808
|
return super.toPathStep(ctx);
|
|
2746
2809
|
}
|
|
2747
2810
|
};
|
|
2748
2811
|
var RenderItNode = class extends RenderViewId {
|
|
2749
2812
|
render(stack, rx) {
|
|
2750
|
-
const
|
|
2751
|
-
|
|
2813
|
+
const base = stack.pendingFrame ? stack.renderPath.toTransactionPath() : null;
|
|
2814
|
+
const newStack = stack.enter(stack.it, {}, true, stack.renderPath, false);
|
|
2815
|
+
return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
|
|
2752
2816
|
}
|
|
2753
2817
|
toPathStep(ctx) {
|
|
2754
2818
|
const next = ctx.next();
|
|
2755
2819
|
if (next === null) return null;
|
|
2756
2820
|
const nextNode = next.resolveNode();
|
|
2757
2821
|
if (nextNode instanceof EachNode && next.hasKey) {
|
|
2758
|
-
if (nextNode.val instanceof DynVal)
|
|
2759
|
-
return dynRenderStep(ctx.comp, nextNode.val.name, next.key);
|
|
2822
|
+
if (nextNode.val instanceof DynVal) return null;
|
|
2760
2823
|
return new EachRenderItStep(nextNode.val.name, next.key);
|
|
2761
2824
|
}
|
|
2762
2825
|
return null;
|
|
@@ -2858,11 +2921,19 @@ var EachNode = class extends WrapperNode {
|
|
|
2858
2921
|
this.iterInfo = new IterInfo(val, null, null, null);
|
|
2859
2922
|
}
|
|
2860
2923
|
render(stack, rx) {
|
|
2861
|
-
return rx.renderEachWhen(stack, this
|
|
2924
|
+
return rx.renderEachWhen(stack, this);
|
|
2862
2925
|
}
|
|
2863
2926
|
toPathStep(ctx) {
|
|
2864
2927
|
return ctx.hasKey ? new EachBindStep(this.iterInfo, ctx.key) : null;
|
|
2865
2928
|
}
|
|
2929
|
+
// Where one item lives, for the render path. `@each` re-binds `it` to the item
|
|
2930
|
+
// whether or not the body is a component, so the position moves either way and
|
|
2931
|
+
// the step has to address it — `.rows` iterated at `key` IS `rows[key]`.
|
|
2932
|
+
// Null for a dynamic sequence: `*rows` carries its own absolute path and enters
|
|
2933
|
+
// a continuation frame instead (see Renderer.renderEachWhen).
|
|
2934
|
+
itemStep(key) {
|
|
2935
|
+
return this.val instanceof FieldVal ? new SeqStep(this.val.name, key) : null;
|
|
2936
|
+
}
|
|
2866
2937
|
static register = true;
|
|
2867
2938
|
};
|
|
2868
2939
|
var IterInfo = class {
|
|
@@ -3123,6 +3194,215 @@ function compileModifiers(eventName, names) {
|
|
|
3123
3194
|
};
|
|
3124
3195
|
}
|
|
3125
3196
|
|
|
3197
|
+
// src/stack.js
|
|
3198
|
+
var STOP = /* @__PURE__ */ Symbol("STOP");
|
|
3199
|
+
var NEXT = /* @__PURE__ */ Symbol("NEXT");
|
|
3200
|
+
var DEFAULT_ROUTE = ["dyn", "lex"];
|
|
3201
|
+
function routeLookup(route, lex, dyn) {
|
|
3202
|
+
for (let i = 0; i < route.length; i++) {
|
|
3203
|
+
const leg = route[i];
|
|
3204
|
+
if (leg === "dyn") {
|
|
3205
|
+
const v = dyn();
|
|
3206
|
+
if (v != null) return v;
|
|
3207
|
+
} else if (leg === "lex") {
|
|
3208
|
+
const v = lex();
|
|
3209
|
+
if (v != null) return v;
|
|
3210
|
+
} else {
|
|
3211
|
+
console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
return null;
|
|
3215
|
+
}
|
|
3216
|
+
var isTypeName = (s) => {
|
|
3217
|
+
const c = s.charCodeAt(0);
|
|
3218
|
+
return c >= 65 && c <= 90;
|
|
3219
|
+
};
|
|
3220
|
+
function lookup(chain, name, dv = null) {
|
|
3221
|
+
let n = chain;
|
|
3222
|
+
while (n !== null) {
|
|
3223
|
+
const r = n[0].lookup(name);
|
|
3224
|
+
if (r === STOP) return dv;
|
|
3225
|
+
if (r !== NEXT) return r;
|
|
3226
|
+
n = n[1];
|
|
3227
|
+
}
|
|
3228
|
+
return dv;
|
|
3229
|
+
}
|
|
3230
|
+
var BindFrame = class {
|
|
3231
|
+
constructor(it, binds, isFrame) {
|
|
3232
|
+
this.it = it;
|
|
3233
|
+
this.binds = binds;
|
|
3234
|
+
this.isFrame = isFrame;
|
|
3235
|
+
}
|
|
3236
|
+
lookup(name) {
|
|
3237
|
+
const v = this.binds[name];
|
|
3238
|
+
return v === void 0 ? this.isFrame ? STOP : NEXT : v;
|
|
3239
|
+
}
|
|
3240
|
+
};
|
|
3241
|
+
var DynFrame = class {
|
|
3242
|
+
constructor(binds, types) {
|
|
3243
|
+
this.binds = binds;
|
|
3244
|
+
this.types = types;
|
|
3245
|
+
}
|
|
3246
|
+
lookup(name) {
|
|
3247
|
+
const v = (isTypeName(name) ? this.types : this.binds)[name];
|
|
3248
|
+
return v === void 0 ? NEXT : v;
|
|
3249
|
+
}
|
|
3250
|
+
};
|
|
3251
|
+
function computeViewsId(views) {
|
|
3252
|
+
let s = "";
|
|
3253
|
+
let n = views;
|
|
3254
|
+
while (n !== null) {
|
|
3255
|
+
s += n[0];
|
|
3256
|
+
n = n[1];
|
|
3257
|
+
}
|
|
3258
|
+
return s === "main" ? "" : s;
|
|
3259
|
+
}
|
|
3260
|
+
var Stack = class _Stack {
|
|
3261
|
+
constructor(fields) {
|
|
3262
|
+
Object.assign(this, fields);
|
|
3263
|
+
}
|
|
3264
|
+
_with(patch) {
|
|
3265
|
+
return new _Stack({ ...this, ...patch });
|
|
3266
|
+
}
|
|
3267
|
+
// Evaluate every provide the entered component publishes and push them as one
|
|
3268
|
+
// dynBinds frame, keyed by NAME. A value is published together with the absolute
|
|
3269
|
+
// path it lives at: the same declaration is read as `*name` AND resumed at by
|
|
3270
|
+
// `<x render="*name">`, so a consumer needs both halves. Types go in the same
|
|
3271
|
+
// frame's other map. No-op with no provides.
|
|
3272
|
+
_pushProvides() {
|
|
3273
|
+
const comp = this.comps.getCompFor(this.it);
|
|
3274
|
+
if (comp == null) return this;
|
|
3275
|
+
const { provide, provideType } = comp;
|
|
3276
|
+
const binds = {};
|
|
3277
|
+
const types = {};
|
|
3278
|
+
let has2 = false;
|
|
3279
|
+
const base = this._publishBase();
|
|
3280
|
+
for (const k in provide) {
|
|
3281
|
+
const step = provide[k].val.toPathItem?.() ?? null;
|
|
3282
|
+
if (step === null) continue;
|
|
3283
|
+
const value = provide[k].val.eval(this);
|
|
3284
|
+
binds[k] = { value, path: base === null ? null : base.concat([step]) };
|
|
3285
|
+
has2 = true;
|
|
3286
|
+
}
|
|
3287
|
+
for (const k in provideType) {
|
|
3288
|
+
types[k] = provideType[k];
|
|
3289
|
+
has2 = true;
|
|
3290
|
+
}
|
|
3291
|
+
if (!has2) return this;
|
|
3292
|
+
return this._with({ dynBinds: [new DynFrame(binds, types), this.dynBinds] });
|
|
3293
|
+
}
|
|
3294
|
+
// The absolute address of the component being entered, or null when this
|
|
3295
|
+
// position cannot be written down as one. Frame-only steps carry bindings and
|
|
3296
|
+
// address nothing, so they are compacted away first; what is left is checked
|
|
3297
|
+
// against the value actually being rendered, because a scope CAN move the
|
|
3298
|
+
// render position without contributing an addressing step (a plain `@each`
|
|
3299
|
+
// body re-binds `it` to the item while its rebuild step is an identity).
|
|
3300
|
+
//
|
|
3301
|
+
// A null base still publishes the VALUE — `*name` reads it fine — but there is
|
|
3302
|
+
// nowhere to resume, so `<x render="*name">` renders nothing rather than
|
|
3303
|
+
// editing whatever happens to live at the address we guessed.
|
|
3304
|
+
_publishBase() {
|
|
3305
|
+
const base = this.renderPath.toTransactionPath().compact();
|
|
3306
|
+
return base.lookup(this.root, NOT_FOUND) === this.it ? base : null;
|
|
3307
|
+
}
|
|
3308
|
+
static root(comps, it, ctx = null) {
|
|
3309
|
+
return new _Stack({
|
|
3310
|
+
comps,
|
|
3311
|
+
root: it,
|
|
3312
|
+
it,
|
|
3313
|
+
binds: [new BindFrame(it, {}, true), null],
|
|
3314
|
+
dynBinds: [new DynFrame({}, {}), null],
|
|
3315
|
+
views: ["main", null],
|
|
3316
|
+
viewsId: "",
|
|
3317
|
+
renderPath: new DispatchPath(),
|
|
3318
|
+
pendingFrame: false,
|
|
3319
|
+
ctx
|
|
3320
|
+
})._pushProvides();
|
|
3321
|
+
}
|
|
3322
|
+
// `renderPath` defaults to this stack's own: an ordinary scope does not move.
|
|
3323
|
+
// `pendingFrame` clears on a component frame (which emits the base) and is
|
|
3324
|
+
// inherited by transparent scopes, which have to carry it to the next boundary.
|
|
3325
|
+
enter(it, bindings = {}, isFrame = true, renderPath = this.renderPath, pendingFrame = null) {
|
|
3326
|
+
const stack = this._with({
|
|
3327
|
+
it,
|
|
3328
|
+
binds: [new BindFrame(it, bindings, isFrame), this.binds],
|
|
3329
|
+
renderPath,
|
|
3330
|
+
pendingFrame: pendingFrame ?? (isFrame ? false : this.pendingFrame)
|
|
3331
|
+
});
|
|
3332
|
+
return isFrame ? stack._pushProvides() : stack;
|
|
3333
|
+
}
|
|
3334
|
+
pushViewName(name) {
|
|
3335
|
+
const views = [name, this.views];
|
|
3336
|
+
return this._with({ views, viewsId: computeViewsId(views) });
|
|
3337
|
+
}
|
|
3338
|
+
// Published types are stable per scope and would only churn the render cache, so
|
|
3339
|
+
// the cache key covers values alone.
|
|
3340
|
+
_pushDynBindValuesToArray(arr, comp) {
|
|
3341
|
+
for (const k in comp.provide) arr.push(this.lookupDynamic(k));
|
|
3342
|
+
for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
|
|
3343
|
+
}
|
|
3344
|
+
// `*name`: the nearest binding above (including this component's own provides,
|
|
3345
|
+
// pushed on entering it), else a path registered in the component's lexical
|
|
3346
|
+
// scope, else this component's declared default, else null.
|
|
3347
|
+
//
|
|
3348
|
+
// One chain walk and no producer resolution: a lookup names what it WANTS, so the
|
|
3349
|
+
// frame it wants is keyed by that name. The default belongs to the CONSUMER's
|
|
3350
|
+
// declaration and is evaluated against the consumer's stack, which is why it is
|
|
3351
|
+
// consulted only after the whole chain has missed.
|
|
3352
|
+
lookupDynamicLocated(name) {
|
|
3353
|
+
if (isTypeName(name)) return null;
|
|
3354
|
+
const v = lookup(this.dynBinds, name);
|
|
3355
|
+
if (v != null) return v;
|
|
3356
|
+
const comp = this.comps.getCompFor(this.it);
|
|
3357
|
+
if (comp == null) return null;
|
|
3358
|
+
const path2 = comp.scope?.lookupPath?.(name) ?? null;
|
|
3359
|
+
if (path2 !== null) {
|
|
3360
|
+
const value2 = path2.lookup(this.root, NOT_FOUND);
|
|
3361
|
+
if (value2 !== NOT_FOUND) return { value: value2, path: path2 };
|
|
3362
|
+
}
|
|
3363
|
+
const dval = comp.lookup[name]?.val ?? null;
|
|
3364
|
+
if (dval === null) return null;
|
|
3365
|
+
const step = dval.toPathItem?.() ?? null;
|
|
3366
|
+
const value = dval.eval(this);
|
|
3367
|
+
return step === null ? { value, path: null } : { value, path: this.renderPath.toTransactionPath().concat([step]) };
|
|
3368
|
+
}
|
|
3369
|
+
lookupDynamic(name) {
|
|
3370
|
+
if (isTypeName(name)) return lookup(this.dynBinds, name);
|
|
3371
|
+
return this.lookupDynamicLocated(name)?.value ?? null;
|
|
3372
|
+
}
|
|
3373
|
+
lookupBind(name) {
|
|
3374
|
+
return lookup(this.binds, name);
|
|
3375
|
+
}
|
|
3376
|
+
lookupFieldRaw(name) {
|
|
3377
|
+
return this.it[name] ?? null;
|
|
3378
|
+
}
|
|
3379
|
+
lookupMethod(name) {
|
|
3380
|
+
const fn = this.it[name];
|
|
3381
|
+
return fn instanceof Function ? fn.call(this.it) : null;
|
|
3382
|
+
}
|
|
3383
|
+
// The dispatched DOM event / drag info, read only by EventMemberVal's
|
|
3384
|
+
// `e.<member>` handler args. Null outside a live event transaction.
|
|
3385
|
+
lookupEvent() {
|
|
3386
|
+
return this.ctx?.event ?? null;
|
|
3387
|
+
}
|
|
3388
|
+
lookupDragInfo() {
|
|
3389
|
+
return this.ctx?.dragInfo ?? null;
|
|
3390
|
+
}
|
|
3391
|
+
getHandlerFor(name, key) {
|
|
3392
|
+
return this.comps.getHandlerFor(this.it, name, key);
|
|
3393
|
+
}
|
|
3394
|
+
lookupBestView(views, defaultViewName) {
|
|
3395
|
+
let n = this.views;
|
|
3396
|
+
while (n !== null) {
|
|
3397
|
+
const view = views[n[0]];
|
|
3398
|
+
if (view !== void 0) return view;
|
|
3399
|
+
n = n[1];
|
|
3400
|
+
}
|
|
3401
|
+
return views[defaultViewName];
|
|
3402
|
+
}
|
|
3403
|
+
};
|
|
3404
|
+
var NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
|
|
3405
|
+
|
|
3126
3406
|
// src/components.js
|
|
3127
3407
|
var COMPONENT = /* @__PURE__ */ Symbol.for("tutuca.component");
|
|
3128
3408
|
var Components = class {
|
|
@@ -3161,12 +3441,14 @@ var ComponentStack = class _ComponentStack {
|
|
|
3161
3441
|
this.byName = {};
|
|
3162
3442
|
this.intentsByName = {};
|
|
3163
3443
|
this.macros = {};
|
|
3444
|
+
this.paths = {};
|
|
3164
3445
|
}
|
|
3165
3446
|
enter() {
|
|
3166
3447
|
return new _ComponentStack(this.comps, this);
|
|
3167
3448
|
}
|
|
3168
3449
|
registerComponents(comps, opts) {
|
|
3169
|
-
const { aliases = {} } = opts ?? {};
|
|
3450
|
+
const { aliases = {}, paths } = opts ?? {};
|
|
3451
|
+
if (paths) this.registerPaths(paths);
|
|
3170
3452
|
for (let i = 0; i < comps.length; i++) {
|
|
3171
3453
|
const Comp = comps[i];
|
|
3172
3454
|
Comp[COMPONENT].scope = this.enter();
|
|
@@ -3180,6 +3462,27 @@ var ComponentStack = class _ComponentStack {
|
|
|
3180
3462
|
else console.warn("alias", alias, "to inexistent component", aliases[alias]);
|
|
3181
3463
|
}
|
|
3182
3464
|
}
|
|
3465
|
+
// Register lowercase names as absolute paths from the app state root. A
|
|
3466
|
+
// descendant that declares one in its `lookup` reads and renders `*name` without
|
|
3467
|
+
// anything above it publishing one — which is what makes a session, a theme or a
|
|
3468
|
+
// host-owned value available in its natural registration scope, instead of forcing
|
|
3469
|
+
// an application root whose only job is to `provide` it. Register on a nested
|
|
3470
|
+
// scope to narrow a name; nearest registration wins.
|
|
3471
|
+
//
|
|
3472
|
+
// Uppercase names are ignored: a component TYPE is what `lookupComponent` already
|
|
3473
|
+
// answers, and a type has no path.
|
|
3474
|
+
registerPaths(paths) {
|
|
3475
|
+
for (const name in paths) {
|
|
3476
|
+
if (isTypeName(name)) {
|
|
3477
|
+
console.warn("registerPaths: a type name has no path", name);
|
|
3478
|
+
continue;
|
|
3479
|
+
}
|
|
3480
|
+
this.paths[name] = paths[name].toPath?.() ?? paths[name];
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
lookupPath(name) {
|
|
3484
|
+
return this.paths[name] ?? this.parent?.lookupPath(name) ?? null;
|
|
3485
|
+
}
|
|
3183
3486
|
registerMacros(macros) {
|
|
3184
3487
|
for (const key in macros) {
|
|
3185
3488
|
const lower = key.toLowerCase();
|
|
@@ -3211,17 +3514,16 @@ var ComponentStack = class _ComponentStack {
|
|
|
3211
3514
|
lookupComponent(name) {
|
|
3212
3515
|
return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
|
|
3213
3516
|
}
|
|
3214
|
-
//
|
|
3215
|
-
// names
|
|
3216
|
-
//
|
|
3217
|
-
//
|
|
3218
|
-
//
|
|
3219
|
-
|
|
3517
|
+
// Whether anything in this scope chain provides `name`. Existence only: a lookup
|
|
3518
|
+
// names what it WANTS and takes whoever is nearest above it at render time, so
|
|
3519
|
+
// there is no producer to identify — several components may publish one name and
|
|
3520
|
+
// the live render ancestry decides. Used by the linter to tell a lookup that can
|
|
3521
|
+
// be satisfied from one that never will be.
|
|
3522
|
+
hasProvider(name) {
|
|
3220
3523
|
for (const compName in this.byName) {
|
|
3221
|
-
|
|
3222
|
-
if (Comp.provide?.[name] !== void 0) return Comp;
|
|
3524
|
+
if (this.byName[compName].provide?.[name] !== void 0) return true;
|
|
3223
3525
|
}
|
|
3224
|
-
return this.parent?.
|
|
3526
|
+
return this.parent?.hasProvider(name) ?? false;
|
|
3225
3527
|
}
|
|
3226
3528
|
lookupMacro(name) {
|
|
3227
3529
|
return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
|
|
@@ -3238,10 +3540,6 @@ var LookupInfo = class {
|
|
|
3238
3540
|
}
|
|
3239
3541
|
};
|
|
3240
3542
|
var isString = (v) => typeof v === "string";
|
|
3241
|
-
var isTypeName = (s) => {
|
|
3242
|
-
const c = s.charCodeAt(0);
|
|
3243
|
-
return c >= 65 && c <= 90;
|
|
3244
|
-
};
|
|
3245
3543
|
var _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
|
|
3246
3544
|
var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
|
|
3247
3545
|
var _compId = 0;
|
|
@@ -3314,160 +3612,6 @@ var Component = class {
|
|
|
3314
3612
|
}
|
|
3315
3613
|
};
|
|
3316
3614
|
|
|
3317
|
-
// src/stack.js
|
|
3318
|
-
var STOP = /* @__PURE__ */ Symbol("STOP");
|
|
3319
|
-
var NEXT = /* @__PURE__ */ Symbol("NEXT");
|
|
3320
|
-
var DEFAULT_ROUTE = ["dyn", "lex"];
|
|
3321
|
-
function routeLookup(route, lex, dyn) {
|
|
3322
|
-
for (let i = 0; i < route.length; i++) {
|
|
3323
|
-
const leg = route[i];
|
|
3324
|
-
if (leg === "dyn") {
|
|
3325
|
-
const v = dyn();
|
|
3326
|
-
if (v != null) return v;
|
|
3327
|
-
} else if (leg === "lex") {
|
|
3328
|
-
const v = lex();
|
|
3329
|
-
if (v != null) return v;
|
|
3330
|
-
} else {
|
|
3331
|
-
console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
|
|
3332
|
-
}
|
|
3333
|
-
}
|
|
3334
|
-
return null;
|
|
3335
|
-
}
|
|
3336
|
-
function lookup(chain, name, dv = null) {
|
|
3337
|
-
let n = chain;
|
|
3338
|
-
while (n !== null) {
|
|
3339
|
-
const r = n[0].lookup(name);
|
|
3340
|
-
if (r === STOP) return dv;
|
|
3341
|
-
if (r !== NEXT) return r;
|
|
3342
|
-
n = n[1];
|
|
3343
|
-
}
|
|
3344
|
-
return dv;
|
|
3345
|
-
}
|
|
3346
|
-
var BindFrame = class {
|
|
3347
|
-
constructor(it, binds, isFrame) {
|
|
3348
|
-
this.it = it;
|
|
3349
|
-
this.binds = binds;
|
|
3350
|
-
this.isFrame = isFrame;
|
|
3351
|
-
}
|
|
3352
|
-
lookup(name) {
|
|
3353
|
-
const v = this.binds[name];
|
|
3354
|
-
return v === void 0 ? this.isFrame ? STOP : NEXT : v;
|
|
3355
|
-
}
|
|
3356
|
-
};
|
|
3357
|
-
var ObjectFrame = class {
|
|
3358
|
-
constructor(binds) {
|
|
3359
|
-
this.binds = binds;
|
|
3360
|
-
}
|
|
3361
|
-
lookup(key) {
|
|
3362
|
-
const v = this.binds[key];
|
|
3363
|
-
return v === void 0 ? NEXT : v;
|
|
3364
|
-
}
|
|
3365
|
-
};
|
|
3366
|
-
function computeViewsId(views) {
|
|
3367
|
-
let s = "";
|
|
3368
|
-
let n = views;
|
|
3369
|
-
while (n !== null) {
|
|
3370
|
-
s += n[0];
|
|
3371
|
-
n = n[1];
|
|
3372
|
-
}
|
|
3373
|
-
return s === "main" ? "" : s;
|
|
3374
|
-
}
|
|
3375
|
-
var Stack = class _Stack {
|
|
3376
|
-
constructor(comps, it, binds, dynBinds, views, viewsId, ctx = null) {
|
|
3377
|
-
this.comps = comps;
|
|
3378
|
-
this.it = it;
|
|
3379
|
-
this.binds = binds;
|
|
3380
|
-
this.dynBinds = dynBinds;
|
|
3381
|
-
this.views = views;
|
|
3382
|
-
this.viewsId = viewsId;
|
|
3383
|
-
this.ctx = ctx;
|
|
3384
|
-
}
|
|
3385
|
-
// Evaluate every provide the entered component publishes and push them as one
|
|
3386
|
-
// dynBinds frame, keyed by NAME. Published types go in the same frame: a type name
|
|
3387
|
-
// starts A-Z and a value name does not, so the two namespaces cannot collide and
|
|
3388
|
-
// nearest-ancestor-wins falls out of frame order for both. No-op with no provides.
|
|
3389
|
-
_pushProvides() {
|
|
3390
|
-
const comp = this.comps.getCompFor(this.it);
|
|
3391
|
-
if (comp == null) return this;
|
|
3392
|
-
const { provide, provideType } = comp;
|
|
3393
|
-
const dynObj = {};
|
|
3394
|
-
let has2 = false;
|
|
3395
|
-
for (const k in provide) {
|
|
3396
|
-
dynObj[k] = provide[k].val.eval(this);
|
|
3397
|
-
has2 = true;
|
|
3398
|
-
}
|
|
3399
|
-
for (const k in provideType) {
|
|
3400
|
-
dynObj[k] = provideType[k];
|
|
3401
|
-
has2 = true;
|
|
3402
|
-
}
|
|
3403
|
-
if (!has2) return this;
|
|
3404
|
-
const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
|
|
3405
|
-
const { comps, it, binds, views, viewsId, ctx } = this;
|
|
3406
|
-
return new _Stack(comps, it, binds, newDynBinds, views, viewsId, ctx);
|
|
3407
|
-
}
|
|
3408
|
-
static root(comps, it, ctx) {
|
|
3409
|
-
const binds = [new BindFrame(it, {}, true), null];
|
|
3410
|
-
const dynBinds = [new ObjectFrame({}), null];
|
|
3411
|
-
const views = ["main", null];
|
|
3412
|
-
return new _Stack(comps, it, binds, dynBinds, views, "", ctx)._pushProvides();
|
|
3413
|
-
}
|
|
3414
|
-
enter(it, bindings = {}, isFrame = true) {
|
|
3415
|
-
const { comps, binds, dynBinds, views, viewsId, ctx } = this;
|
|
3416
|
-
const newBinds = [new BindFrame(it, bindings, isFrame), binds];
|
|
3417
|
-
const stack = new _Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx);
|
|
3418
|
-
return isFrame ? stack._pushProvides() : stack;
|
|
3419
|
-
}
|
|
3420
|
-
pushViewName(name) {
|
|
3421
|
-
const { comps, it, binds, dynBinds, views, ctx } = this;
|
|
3422
|
-
const newViews = [name, views];
|
|
3423
|
-
return new _Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
|
|
3424
|
-
}
|
|
3425
|
-
// Published types are stable per scope and would only churn the render cache, so
|
|
3426
|
-
// the cache key covers values alone.
|
|
3427
|
-
_pushDynBindValuesToArray(arr, comp) {
|
|
3428
|
-
for (const k in comp.provide) arr.push(this.lookupDynamic(k));
|
|
3429
|
-
for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
|
|
3430
|
-
}
|
|
3431
|
-
// `*name`: the nearest binding above (including this component's own provides,
|
|
3432
|
-
// pushed on entering it), else this component's declared default, else null.
|
|
3433
|
-
lookupDynamic(name) {
|
|
3434
|
-
const v = lookup(this.dynBinds, name);
|
|
3435
|
-
if (v != null) return v;
|
|
3436
|
-
const comp = this.comps.getCompFor(this.it);
|
|
3437
|
-
return comp?.lookup[name]?.val?.eval(this) ?? null;
|
|
3438
|
-
}
|
|
3439
|
-
lookupBind(name) {
|
|
3440
|
-
return lookup(this.binds, name);
|
|
3441
|
-
}
|
|
3442
|
-
lookupFieldRaw(name) {
|
|
3443
|
-
return this.it[name] ?? null;
|
|
3444
|
-
}
|
|
3445
|
-
lookupMethod(name) {
|
|
3446
|
-
const fn = this.it[name];
|
|
3447
|
-
return fn instanceof Function ? fn.call(this.it) : null;
|
|
3448
|
-
}
|
|
3449
|
-
// The dispatched DOM event / drag info, read only by EventMemberVal's
|
|
3450
|
-
// `e.<member>` handler args. Null outside a live event transaction.
|
|
3451
|
-
lookupEvent() {
|
|
3452
|
-
return this.ctx?.event ?? null;
|
|
3453
|
-
}
|
|
3454
|
-
lookupDragInfo() {
|
|
3455
|
-
return this.ctx?.dragInfo ?? null;
|
|
3456
|
-
}
|
|
3457
|
-
getHandlerFor(name, key) {
|
|
3458
|
-
return this.comps.getHandlerFor(this.it, name, key);
|
|
3459
|
-
}
|
|
3460
|
-
lookupBestView(views, defaultViewName) {
|
|
3461
|
-
let n = this.views;
|
|
3462
|
-
while (n !== null) {
|
|
3463
|
-
const view = views[n[0]];
|
|
3464
|
-
if (view !== void 0) return view;
|
|
3465
|
-
n = n[1];
|
|
3466
|
-
}
|
|
3467
|
-
return views[defaultViewName];
|
|
3468
|
-
}
|
|
3469
|
-
};
|
|
3470
|
-
|
|
3471
3615
|
// src/oo.js
|
|
3472
3616
|
var BAD_VALUE = /* @__PURE__ */ Symbol("BadValue");
|
|
3473
3617
|
var nullCoercer = (v) => v;
|
|
@@ -3500,9 +3644,22 @@ var CHECK_TYPE_LIST = Array.isArray;
|
|
|
3500
3644
|
var CHECK_TYPE_OBJECT = isPlainObject;
|
|
3501
3645
|
var CHECK_TYPE_MAP = (v) => v instanceof Map;
|
|
3502
3646
|
var CHECK_TYPE_SET = (v) => v instanceof Set;
|
|
3647
|
+
var COERCE_NONE = (_v) => null;
|
|
3648
|
+
var COERCE_BOOL = (v) => !!v;
|
|
3649
|
+
var COERCE_STRING = (v) => v?.toString?.() ?? "";
|
|
3650
|
+
var COERCE_INT = (v) => Number.isFinite(v) ? Math.trunc(v) : null;
|
|
3651
|
+
var COERCE_LIST = (v) => Array.isArray(v) ? [...v] : null;
|
|
3652
|
+
var COERCE_OBJECT = (v) => isPlainObject(v) ? { ...v } : null;
|
|
3653
|
+
var COERCE_MAP = (v) => {
|
|
3654
|
+
if (v instanceof Map) return new Map(v);
|
|
3655
|
+
if (Array.isArray(v) || isPlainObject(v))
|
|
3656
|
+
return new Map(Array.isArray(v) ? v : Object.entries(v));
|
|
3657
|
+
return null;
|
|
3658
|
+
};
|
|
3659
|
+
var COERCE_SET = (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null;
|
|
3503
3660
|
var FieldBool = class extends Field {
|
|
3504
3661
|
constructor(name, defaultValue = false) {
|
|
3505
|
-
super("bool", name, CHECK_TYPE_BOOL,
|
|
3662
|
+
super("bool", name, CHECK_TYPE_BOOL, COERCE_BOOL, defaultValue);
|
|
3506
3663
|
}
|
|
3507
3664
|
};
|
|
3508
3665
|
var FieldAny = class extends Field {
|
|
@@ -3512,23 +3669,17 @@ var FieldAny = class extends Field {
|
|
|
3512
3669
|
};
|
|
3513
3670
|
var FieldString = class extends Field {
|
|
3514
3671
|
constructor(name, defaultValue = "") {
|
|
3515
|
-
super("text", name, CHECK_TYPE_STRING,
|
|
3672
|
+
super("text", name, CHECK_TYPE_STRING, COERCE_STRING, defaultValue);
|
|
3516
3673
|
}
|
|
3517
3674
|
};
|
|
3518
3675
|
var FieldInt = class extends Field {
|
|
3519
3676
|
constructor(name, defaultValue = 0) {
|
|
3520
|
-
super(
|
|
3521
|
-
"int",
|
|
3522
|
-
name,
|
|
3523
|
-
CHECK_TYPE_INT,
|
|
3524
|
-
(v) => Number.isFinite(v) ? Math.trunc(v) : null,
|
|
3525
|
-
defaultValue
|
|
3526
|
-
);
|
|
3677
|
+
super("int", name, CHECK_TYPE_INT, COERCE_INT, defaultValue);
|
|
3527
3678
|
}
|
|
3528
3679
|
};
|
|
3529
3680
|
var FieldFloat = class extends Field {
|
|
3530
3681
|
constructor(name, defaultValue = 0) {
|
|
3531
|
-
super("float", name, CHECK_TYPE_FLOAT,
|
|
3682
|
+
super("float", name, CHECK_TYPE_FLOAT, COERCE_NONE, defaultValue);
|
|
3532
3683
|
}
|
|
3533
3684
|
};
|
|
3534
3685
|
var metaOf = (v) => v?.constructor?.[COMPONENT] ?? v?.constructor?.getMetaClass?.();
|
|
@@ -3541,45 +3692,22 @@ var FieldComp = class extends Field {
|
|
|
3541
3692
|
};
|
|
3542
3693
|
var FieldList = class extends Field {
|
|
3543
3694
|
constructor(name, defaultValue = []) {
|
|
3544
|
-
super("list", name, CHECK_TYPE_LIST,
|
|
3695
|
+
super("list", name, CHECK_TYPE_LIST, COERCE_LIST, defaultValue);
|
|
3545
3696
|
}
|
|
3546
3697
|
};
|
|
3547
3698
|
var FieldObject = class extends Field {
|
|
3548
3699
|
constructor(name, defaultValue = {}) {
|
|
3549
|
-
super(
|
|
3550
|
-
"object",
|
|
3551
|
-
name,
|
|
3552
|
-
CHECK_TYPE_OBJECT,
|
|
3553
|
-
(v) => isPlainObject(v) ? { ...v } : null,
|
|
3554
|
-
defaultValue
|
|
3555
|
-
);
|
|
3700
|
+
super("object", name, CHECK_TYPE_OBJECT, COERCE_OBJECT, defaultValue);
|
|
3556
3701
|
}
|
|
3557
3702
|
};
|
|
3558
3703
|
var FieldMap = class extends Field {
|
|
3559
3704
|
constructor(name, defaultValue = /* @__PURE__ */ new Map()) {
|
|
3560
|
-
super(
|
|
3561
|
-
"map",
|
|
3562
|
-
name,
|
|
3563
|
-
CHECK_TYPE_MAP,
|
|
3564
|
-
(v) => {
|
|
3565
|
-
if (v instanceof Map) return new Map(v);
|
|
3566
|
-
if (Array.isArray(v) || isPlainObject(v))
|
|
3567
|
-
return new Map(Array.isArray(v) ? v : Object.entries(v));
|
|
3568
|
-
return null;
|
|
3569
|
-
},
|
|
3570
|
-
defaultValue
|
|
3571
|
-
);
|
|
3705
|
+
super("map", name, CHECK_TYPE_MAP, COERCE_MAP, defaultValue);
|
|
3572
3706
|
}
|
|
3573
3707
|
};
|
|
3574
3708
|
var FieldSet = class extends Field {
|
|
3575
3709
|
constructor(name, defaultValue = /* @__PURE__ */ new Set()) {
|
|
3576
|
-
super(
|
|
3577
|
-
"set",
|
|
3578
|
-
name,
|
|
3579
|
-
CHECK_TYPE_SET,
|
|
3580
|
-
(v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null,
|
|
3581
|
-
defaultValue
|
|
3582
|
-
);
|
|
3710
|
+
super("set", name, CHECK_TYPE_SET, COERCE_SET, defaultValue);
|
|
3583
3711
|
}
|
|
3584
3712
|
};
|
|
3585
3713
|
function mkCompField(field, scope, args) {
|
|
@@ -3677,8 +3805,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
|
|
|
3677
3805
|
const value = fields[field];
|
|
3678
3806
|
const type = typeof value;
|
|
3679
3807
|
if (type === "string") b.addField(field, value, FieldString);
|
|
3680
|
-
else if (type === "number")
|
|
3681
|
-
b.addField(field, value, Number.isInteger(value) ? FieldInt : FieldFloat);
|
|
3808
|
+
else if (type === "number") b.addField(field, value, FieldFloat);
|
|
3682
3809
|
else if (type === "boolean") b.addField(field, value, FieldBool);
|
|
3683
3810
|
else if (Array.isArray(value)) b.addField(field, [...value], FieldList);
|
|
3684
3811
|
else if (value instanceof Set) b.addField(field, new Set(value), FieldSet);
|
|
@@ -3830,9 +3957,9 @@ var Transactor = class {
|
|
|
3830
3957
|
// `.a[.selId]` render target reconstructed from a DOM event) against the root the
|
|
3831
3958
|
// handler read, so pathKeys carries concrete keys instead of dropping the dynamic
|
|
3832
3959
|
// step. No-op when nobody is observing.
|
|
3833
|
-
_emitRecord(root, { kind, name, args, path, targetPath, handler, handlerName, matched, before, after, parent }) {
|
|
3960
|
+
_emitRecord(root, { kind, name, args, path: path2, targetPath, handler, handlerName, matched, before, after, parent }) {
|
|
3834
3961
|
if (this._observers.length === 0) return;
|
|
3835
|
-
const pinned =
|
|
3962
|
+
const pinned = path2.pinKeys(root);
|
|
3836
3963
|
this._emit({
|
|
3837
3964
|
kind,
|
|
3838
3965
|
name,
|
|
@@ -3883,18 +4010,20 @@ var Transactor = class {
|
|
|
3883
4010
|
// intent's answerPath is: a reply must reach the sender that asked even if a key
|
|
3884
4011
|
// moved while the message was in flight. Null when nobody is waiting — a host
|
|
3885
4012
|
// sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
|
|
3886
|
-
pushSend(
|
|
3887
|
-
const t = new SendEvent(
|
|
3888
|
-
t.
|
|
4013
|
+
pushSend(path2, name, args = [], parent = null, origin = null, txnPath = null) {
|
|
4014
|
+
const t = new SendEvent(path2, this, name, args, parent);
|
|
4015
|
+
t.txnPath = txnPath;
|
|
4016
|
+
t.origin = origin;
|
|
4017
|
+
t.originPinned = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
|
|
3889
4018
|
this.pushTransaction(t);
|
|
3890
4019
|
return this._link(t, parent);
|
|
3891
4020
|
}
|
|
3892
4021
|
// Raise an intent: a job the sender did not address, walked along a route until
|
|
3893
4022
|
// something answers. `opts.route` is a list of legs (see DEFAULT_ROUTE) and
|
|
3894
4023
|
// `opts.livePath` opts out of pinning the answer's destination keys.
|
|
3895
|
-
pushIntent(
|
|
4024
|
+
pushIntent(path2, name, args = [], opts = {}, parent = null) {
|
|
3896
4025
|
const release = parent ? parent.completion.track() : null;
|
|
3897
|
-
const walk = new IntentWalk(this,
|
|
4026
|
+
const walk = new IntentWalk(this, path2, name, args, opts, parent, release);
|
|
3898
4027
|
walk.advance();
|
|
3899
4028
|
return walk;
|
|
3900
4029
|
}
|
|
@@ -3928,16 +4057,17 @@ var Transactor = class {
|
|
|
3928
4057
|
transaction._completion?.releaseSelf();
|
|
3929
4058
|
}
|
|
3930
4059
|
}
|
|
3931
|
-
transactInputNow(
|
|
3932
|
-
this.transact(new InputEvent(
|
|
4060
|
+
transactInputNow(path2, event, eventHandler, dragInfo) {
|
|
4061
|
+
this.transact(new InputEvent(path2, event, eventHandler, this, dragInfo));
|
|
3933
4062
|
}
|
|
3934
4063
|
};
|
|
3935
4064
|
function nullHandler() {
|
|
3936
4065
|
return this;
|
|
3937
4066
|
}
|
|
3938
4067
|
var Transaction = class {
|
|
3939
|
-
constructor(
|
|
3940
|
-
this.path =
|
|
4068
|
+
constructor(path2, transactor, parentTransaction = null) {
|
|
4069
|
+
this.path = path2;
|
|
4070
|
+
this.txnPath = null;
|
|
3941
4071
|
this.transactor = transactor;
|
|
3942
4072
|
this.parentTransaction = parentTransaction;
|
|
3943
4073
|
this._completion = null;
|
|
@@ -3986,9 +4116,11 @@ var Transaction = class {
|
|
|
3986
4116
|
getHandlerAndArgs(_root, _instance, _comps) {
|
|
3987
4117
|
return null;
|
|
3988
4118
|
}
|
|
3989
|
-
// The path used to apply the mutation
|
|
3990
|
-
//
|
|
4119
|
+
// The path used to apply the mutation: the ACTIVE frame of the dispatch path, so
|
|
4120
|
+
// an event inside a `<x render="*name">` subtree updates the value where it
|
|
4121
|
+
// really lives (the dispatch `this.path` keeps the visual callers, for bubbling).
|
|
3991
4122
|
getTransactionPath() {
|
|
4123
|
+
if (this.txnPath !== null) return this.txnPath;
|
|
3992
4124
|
return this.path.toTransactionPath().compact();
|
|
3993
4125
|
}
|
|
3994
4126
|
run(curRoot, comps) {
|
|
@@ -4006,15 +4138,16 @@ var Transaction = class {
|
|
|
4006
4138
|
}
|
|
4007
4139
|
};
|
|
4008
4140
|
var InputEvent = class extends Transaction {
|
|
4009
|
-
constructor(
|
|
4010
|
-
super(
|
|
4141
|
+
constructor(path2, e, handler, transactor, dragInfo) {
|
|
4142
|
+
super(path2, transactor);
|
|
4011
4143
|
this.e = e;
|
|
4012
4144
|
this.handler = handler;
|
|
4013
4145
|
this.dragInfo = dragInfo;
|
|
4014
4146
|
this._dispatchPath = null;
|
|
4015
4147
|
}
|
|
4016
|
-
// Frame steps removed,
|
|
4017
|
-
//
|
|
4148
|
+
// Frame-only steps removed, one step per crossed component kept — inside every
|
|
4149
|
+
// continuation frame independently, so bubbling it visits every component and
|
|
4150
|
+
// then returns to the caller that wrote the `*name`.
|
|
4018
4151
|
get dispatchPath() {
|
|
4019
4152
|
this._dispatchPath ??= this.path.compact();
|
|
4020
4153
|
return this._dispatchPath;
|
|
@@ -4049,11 +4182,11 @@ var InputEvent = class extends Transaction {
|
|
|
4049
4182
|
this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
|
|
4050
4183
|
}
|
|
4051
4184
|
getHandlerAndArgs(root, _instance, comps) {
|
|
4052
|
-
const stack = this.path.
|
|
4185
|
+
const stack = this.path.buildStack(Stack.root(comps, root, this));
|
|
4053
4186
|
const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
|
|
4054
4187
|
this._handlerArgs = [...args];
|
|
4055
|
-
const
|
|
4056
|
-
args.push(new EventContext(
|
|
4188
|
+
const path2 = this.dispatchPath;
|
|
4189
|
+
args.push(new EventContext(path2, this.transactor, this));
|
|
4057
4190
|
return [handler, args];
|
|
4058
4191
|
}
|
|
4059
4192
|
// The dispatched DOM event, read only through `e.<member>` handler args
|
|
@@ -4064,11 +4197,11 @@ var InputEvent = class extends Transaction {
|
|
|
4064
4197
|
}
|
|
4065
4198
|
};
|
|
4066
4199
|
var NameArgsTransaction = class extends Transaction {
|
|
4067
|
-
constructor(
|
|
4068
|
-
super(
|
|
4200
|
+
constructor(path2, transactor, name, args, parentTransaction) {
|
|
4201
|
+
super(path2, transactor, parentTransaction);
|
|
4069
4202
|
this.name = name;
|
|
4070
4203
|
this.args = args;
|
|
4071
|
-
this.targetPath =
|
|
4204
|
+
this.targetPath = path2;
|
|
4072
4205
|
}
|
|
4073
4206
|
handlerProp = null;
|
|
4074
4207
|
// NameArgs verbs map their handler bucket straight to the observed kind:
|
|
@@ -4125,8 +4258,8 @@ var SendEvent = class extends NameArgsTransaction {
|
|
|
4125
4258
|
};
|
|
4126
4259
|
var IntentEvent = class extends NameArgsTransaction {
|
|
4127
4260
|
handlerProp = "intent";
|
|
4128
|
-
constructor(
|
|
4129
|
-
super(
|
|
4261
|
+
constructor(path2, transactor, walk) {
|
|
4262
|
+
super(path2, transactor, walk.name, walk.args, walk.parent);
|
|
4130
4263
|
this.walk = walk;
|
|
4131
4264
|
this.targetPath = walk.origin;
|
|
4132
4265
|
}
|
|
@@ -4153,17 +4286,17 @@ var PASS = /* @__PURE__ */ Symbol.for("tutuca.intent.pass");
|
|
|
4153
4286
|
var REFUSAL_RING_CAP = 200;
|
|
4154
4287
|
var INTENT_DEPTH = 64;
|
|
4155
4288
|
var IntentWalk = class {
|
|
4156
|
-
constructor(transactor,
|
|
4289
|
+
constructor(transactor, path2, name, args, opts, parent, release) {
|
|
4157
4290
|
this.transactor = transactor;
|
|
4158
4291
|
this.name = name;
|
|
4159
4292
|
this.args = args;
|
|
4160
4293
|
this.route = opts?.route ?? DEFAULT_ROUTE;
|
|
4161
4294
|
this.parent = parent;
|
|
4162
4295
|
this.release = release;
|
|
4163
|
-
this.origin =
|
|
4164
|
-
this.answerPath = opts?.livePath ? null :
|
|
4296
|
+
this.origin = path2;
|
|
4297
|
+
this.answerPath = opts?.livePath ? null : path2.toTransactionPath().pinKeys(transactor.state.val);
|
|
4165
4298
|
this.legIndex = 0;
|
|
4166
|
-
this.dynAt =
|
|
4299
|
+
this.dynAt = path2;
|
|
4167
4300
|
this.hops = 0;
|
|
4168
4301
|
this.ended = false;
|
|
4169
4302
|
}
|
|
@@ -4175,7 +4308,7 @@ var IntentWalk = class {
|
|
|
4175
4308
|
while (this.legIndex < this.route.length) {
|
|
4176
4309
|
const leg = this.route[this.legIndex];
|
|
4177
4310
|
if (leg === "dyn") {
|
|
4178
|
-
if (this.dynAt.
|
|
4311
|
+
if (!this.dynAt.canPop()) {
|
|
4179
4312
|
this.legIndex++;
|
|
4180
4313
|
continue;
|
|
4181
4314
|
}
|
|
@@ -4272,8 +4405,8 @@ var IntentWalk = class {
|
|
|
4272
4405
|
if (this.ended) return;
|
|
4273
4406
|
this.ended = true;
|
|
4274
4407
|
if (name === null) return this.release?.();
|
|
4275
|
-
const
|
|
4276
|
-
|
|
4408
|
+
const t = new SendEvent(this.origin, this.transactor, name, args, this.parent);
|
|
4409
|
+
t.txnPath = this.answerPath;
|
|
4277
4410
|
t._isAnswer = true;
|
|
4278
4411
|
this.transactor.pushTransaction(t);
|
|
4279
4412
|
if (this.release) t.completion.whenSubtreeSettled().then(this.release);
|
|
@@ -4339,8 +4472,8 @@ var Completion = class {
|
|
|
4339
4472
|
}
|
|
4340
4473
|
};
|
|
4341
4474
|
var Dispatcher = class {
|
|
4342
|
-
constructor(
|
|
4343
|
-
this.path =
|
|
4475
|
+
constructor(path2, transactor, parentTransaction, root = transactor.state.val) {
|
|
4476
|
+
this.path = path2;
|
|
4344
4477
|
this.transactor = transactor;
|
|
4345
4478
|
this.parent = parentTransaction;
|
|
4346
4479
|
this.root = root;
|
|
@@ -4368,7 +4501,9 @@ var Dispatcher = class {
|
|
|
4368
4501
|
// replayed; provides are pushed on every component frame either way, so a provide
|
|
4369
4502
|
// that reads a loop binding is the one case this cannot reproduce faithfully.
|
|
4370
4503
|
_stack() {
|
|
4371
|
-
this._stackMemo ??= this.path.
|
|
4504
|
+
this._stackMemo ??= this.path.buildStack(
|
|
4505
|
+
Stack.root(this.transactor.comps, this.root, this.parent)
|
|
4506
|
+
);
|
|
4372
4507
|
return this._stackMemo;
|
|
4373
4508
|
}
|
|
4374
4509
|
// Resolve a name the way the renderer would. `opts.route` takes the same legs in
|
|
@@ -4382,14 +4517,19 @@ var Dispatcher = class {
|
|
|
4382
4517
|
);
|
|
4383
4518
|
}
|
|
4384
4519
|
// The `lex` leg without a Stack: the scope of the component whose handler is
|
|
4385
|
-
// running, which is the leaf of this ctx's path.
|
|
4520
|
+
// running, which is the leaf of this ctx's path. A type name resolves to the
|
|
4521
|
+
// component registered under it; a value name to a path registered under it
|
|
4522
|
+
// (see ComponentStack.registerPaths), read against the current root.
|
|
4386
4523
|
_lookupLex(name) {
|
|
4387
4524
|
let Comp = null;
|
|
4388
4525
|
this.walkPath((c) => {
|
|
4389
4526
|
Comp = c;
|
|
4390
4527
|
return false;
|
|
4391
4528
|
});
|
|
4392
|
-
|
|
4529
|
+
const scope = Comp?.scope;
|
|
4530
|
+
if (scope == null) return null;
|
|
4531
|
+
if (isTypeName(name)) return scope.lookupComponent(name) ?? null;
|
|
4532
|
+
return scope.lookupPath(name)?.lookup(this.root) ?? null;
|
|
4393
4533
|
}
|
|
4394
4534
|
// A component lookup is a value lookup constrained to a component. The `lex` leg
|
|
4395
4535
|
// can only ever answer with one; the `dyn` leg reads a binding an ancestor
|
|
@@ -4411,8 +4551,8 @@ var Dispatcher = class {
|
|
|
4411
4551
|
send(name, args) {
|
|
4412
4552
|
return this.sendAtPath(this.path, name, args);
|
|
4413
4553
|
}
|
|
4414
|
-
sendAtPath(
|
|
4415
|
-
return this.transactor.pushSend(
|
|
4554
|
+
sendAtPath(path2, name, args) {
|
|
4555
|
+
return this.transactor.pushSend(path2, name, args, this.parent, this.path);
|
|
4416
4556
|
}
|
|
4417
4557
|
// An intent is ROUTED: it names a job and walks until something answers. The verb
|
|
4418
4558
|
// does not decide which scope answers — `opts.route` does, written here at the call
|
|
@@ -4420,8 +4560,8 @@ var Dispatcher = class {
|
|
|
4420
4560
|
intent(name, args, opts) {
|
|
4421
4561
|
return this.intentAtPath(this.path, name, args, opts);
|
|
4422
4562
|
}
|
|
4423
|
-
intentAtPath(
|
|
4424
|
-
return this.transactor.pushIntent(
|
|
4563
|
+
intentAtPath(path2, name, args, opts) {
|
|
4564
|
+
return this.transactor.pushIntent(path2, name, args, opts, this.parent);
|
|
4425
4565
|
}
|
|
4426
4566
|
};
|
|
4427
4567
|
var EventContext = class extends Dispatcher {
|
|
@@ -4450,7 +4590,14 @@ var EventContext = class extends Dispatcher {
|
|
|
4450
4590
|
this.transactor.refuse("NO_SENDER", { name });
|
|
4451
4591
|
return null;
|
|
4452
4592
|
}
|
|
4453
|
-
return this.
|
|
4593
|
+
return this.transactor.pushSend(
|
|
4594
|
+
origin,
|
|
4595
|
+
name,
|
|
4596
|
+
args,
|
|
4597
|
+
this.parent,
|
|
4598
|
+
this.path,
|
|
4599
|
+
this.parent.originPinned
|
|
4600
|
+
);
|
|
4454
4601
|
}
|
|
4455
4602
|
// End the walk answering nothing — "served, and no answer".
|
|
4456
4603
|
stop() {
|
|
@@ -4482,7 +4629,7 @@ var PathChanges = class extends PathBuilder {
|
|
|
4482
4629
|
}
|
|
4483
4630
|
};
|
|
4484
4631
|
function rootDispatcher(transactor) {
|
|
4485
|
-
return new Dispatcher(new
|
|
4632
|
+
return new Dispatcher(new DispatchPath(), transactor, null);
|
|
4486
4633
|
}
|
|
4487
4634
|
|
|
4488
4635
|
// src/app.js
|
|
@@ -4523,7 +4670,7 @@ var App = class {
|
|
|
4523
4670
|
const { type } = e;
|
|
4524
4671
|
const isDrag = type === "dragover" || type === "dragstart" || type === "dragend" || type === "drop";
|
|
4525
4672
|
const { rootNode: root, maxEventNodeDepth: maxDepth, comps, transactor } = this;
|
|
4526
|
-
const [
|
|
4673
|
+
const [path2, handlers] = DispatchPath.fromNodeAndEventName(
|
|
4527
4674
|
e.target,
|
|
4528
4675
|
type,
|
|
4529
4676
|
root,
|
|
@@ -4531,9 +4678,9 @@ var App = class {
|
|
|
4531
4678
|
comps,
|
|
4532
4679
|
!isDrag
|
|
4533
4680
|
);
|
|
4534
|
-
if (isDrag) this._handleDragEvent(e, type,
|
|
4535
|
-
if (
|
|
4536
|
-
for (const handler of handlers) transactor.transactInputNow(
|
|
4681
|
+
if (isDrag) this._handleDragEvent(e, type, path2);
|
|
4682
|
+
if (path2 !== null && handlers !== null)
|
|
4683
|
+
for (const handler of handlers) transactor.transactInputNow(path2, e, handler, this.dragInfo);
|
|
4537
4684
|
}
|
|
4538
4685
|
_handleTouchEvent(e) {
|
|
4539
4686
|
const { type } = e;
|
|
@@ -4576,7 +4723,7 @@ var App = class {
|
|
|
4576
4723
|
this._touch = null;
|
|
4577
4724
|
}
|
|
4578
4725
|
}
|
|
4579
|
-
_handleDragEvent(e, type,
|
|
4726
|
+
_handleDragEvent(e, type, path2) {
|
|
4580
4727
|
if (type === "dragover") {
|
|
4581
4728
|
const dropTarget = getClosestDropTarget(e.target, this.rootNode, Infinity);
|
|
4582
4729
|
if (dropTarget !== null) {
|
|
@@ -4588,10 +4735,10 @@ var App = class {
|
|
|
4588
4735
|
} else if (type === "dragstart") {
|
|
4589
4736
|
e.target.dataset.dragging = 1;
|
|
4590
4737
|
const rootValue = this.state.val;
|
|
4591
|
-
const txnPath =
|
|
4738
|
+
const txnPath = path2.compact().toTransactionPath();
|
|
4592
4739
|
const value = txnPath.lookup(rootValue);
|
|
4593
4740
|
const dragType = e.target.dataset.dragtype ?? "?";
|
|
4594
|
-
const stack =
|
|
4741
|
+
const stack = path2.buildStack(this.makeStack(rootValue));
|
|
4595
4742
|
this.dragInfo = new DragInfo(stack, value, dragType, e.target);
|
|
4596
4743
|
} else if (type === "drop") {
|
|
4597
4744
|
e.preventDefault();
|
|
@@ -4666,7 +4813,7 @@ var App = class {
|
|
|
4666
4813
|
this.rootNode.removeEventListener(name, this, listenerOpts(name));
|
|
4667
4814
|
}
|
|
4668
4815
|
sendAtRoot(name, args) {
|
|
4669
|
-
this.transactor.pushSend(new
|
|
4816
|
+
this.transactor.pushSend(new DispatchPath(), name, args);
|
|
4670
4817
|
}
|
|
4671
4818
|
registerComponents(comps, opts) {
|
|
4672
4819
|
const scope = this.compStack.enter();
|
|
@@ -4884,7 +5031,20 @@ var WeakMapDomCache = class {
|
|
|
4884
5031
|
};
|
|
4885
5032
|
|
|
4886
5033
|
// src/renderer.js
|
|
4887
|
-
var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
|
|
5034
|
+
var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk", "rp"];
|
|
5035
|
+
function stampRenderBase(vdom, text) {
|
|
5036
|
+
if (vdom instanceof VNode)
|
|
5037
|
+
return new VNode(
|
|
5038
|
+
vdom.tag,
|
|
5039
|
+
{ ...vdom.attrs, "data-rp": text },
|
|
5040
|
+
vdom.childs,
|
|
5041
|
+
vdom.key,
|
|
5042
|
+
vdom.namespace
|
|
5043
|
+
);
|
|
5044
|
+
if (vdom instanceof VFragment)
|
|
5045
|
+
return new VFragment(vdom.childs.map((c) => stampRenderBase(c, text)));
|
|
5046
|
+
return vdom;
|
|
5047
|
+
}
|
|
4888
5048
|
var Renderer = class {
|
|
4889
5049
|
constructor(comps) {
|
|
4890
5050
|
this.comps = comps;
|
|
@@ -4921,17 +5081,17 @@ var Renderer = class {
|
|
|
4921
5081
|
if (comp === null) return null;
|
|
4922
5082
|
return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
|
|
4923
5083
|
}
|
|
4924
|
-
renderIt(stack, node, key, viewName) {
|
|
5084
|
+
renderIt(stack, node, key, viewName, base = null) {
|
|
4925
5085
|
const comp = this.comps.getCompFor(stack.it);
|
|
4926
|
-
return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
|
|
5086
|
+
return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName, base) : null;
|
|
4927
5087
|
}
|
|
4928
5088
|
// `node` is the parse node of the render site (`<x render>` / `render-it` /
|
|
4929
5089
|
// `render-each`, or the view's root anode for the app root). It keys the
|
|
4930
5090
|
// cache as a globally-unique object: node ids alone are unique only within a
|
|
4931
5091
|
// single view, so the same value rendered by two components (e.g. through a
|
|
4932
5092
|
// shared dynamic-var sequence) would otherwise collide in the cache.
|
|
4933
|
-
_rValComp(stack, val, comp, node, key, viewName) {
|
|
4934
|
-
const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
|
|
5093
|
+
_rValComp(stack, val, comp, node, key, viewName, base = null) {
|
|
5094
|
+
const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}${stack.renderPath.addressKey}`;
|
|
4935
5095
|
const cachePath = [node, val];
|
|
4936
5096
|
stack._pushDynBindValuesToArray(cachePath, comp);
|
|
4937
5097
|
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
@@ -4939,30 +5099,43 @@ var Renderer = class {
|
|
|
4939
5099
|
const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
|
|
4940
5100
|
const body = this.renderView(view, stack);
|
|
4941
5101
|
if (body == null) return null;
|
|
5102
|
+
const baseJson = base === null ? null : pathToJson(base);
|
|
4942
5103
|
const meta = this._renderMetadata({
|
|
4943
5104
|
$: "Comp",
|
|
4944
5105
|
nid: node?.nodeId ?? null,
|
|
4945
5106
|
cid: comp.id,
|
|
4946
|
-
vid: view.name
|
|
5107
|
+
vid: view.name,
|
|
5108
|
+
...baseJson === null ? null : { base: baseJson }
|
|
4947
5109
|
});
|
|
4948
|
-
const dom = new VFragment([
|
|
5110
|
+
const dom = new VFragment([
|
|
5111
|
+
meta,
|
|
5112
|
+
baseJson === null ? body : stampRenderBase(body, JSON.stringify(baseJson))
|
|
5113
|
+
]);
|
|
4949
5114
|
this.cache.set(cachePath, cacheKey, dom);
|
|
4950
5115
|
return dom;
|
|
4951
5116
|
}
|
|
4952
5117
|
pushEachEntry(r, nid, attrName, key, dom) {
|
|
4953
5118
|
r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
|
|
4954
5119
|
}
|
|
4955
|
-
renderEachWhen(stack,
|
|
5120
|
+
renderEachWhen(stack, each2) {
|
|
5121
|
+
const { iterInfo, node: view, nodeId: nid } = each2;
|
|
4956
5122
|
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
5123
|
+
const seqPath = iterInfo.val instanceof DynVal ? stack.lookupDynamicLocated(iterInfo.val.name)?.path ?? null : null;
|
|
4957
5124
|
const r = [];
|
|
4958
5125
|
const it = stack.it;
|
|
4959
5126
|
const renderOne = (key, value, attrName, binds) => {
|
|
5127
|
+
const itemBase = seqPath === null ? null : keyedPath(seqPath, key);
|
|
5128
|
+
const itemStep = itemBase === null ? each2.itemStep(key) : null;
|
|
5129
|
+
const itemPath = itemBase !== null ? stack.renderPath.pushFrame(itemBase) : itemStep !== null ? stack.renderPath.pushItem(itemStep) : stack.renderPath;
|
|
4960
5130
|
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
4961
|
-
const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
|
|
5131
|
+
const cacheKey = `${stack.viewsId ?? ""}${nid}${key}${itemPath.addressKey}`;
|
|
4962
5132
|
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
4963
5133
|
if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
4964
5134
|
else {
|
|
4965
|
-
const dom = this.renderView(
|
|
5135
|
+
const dom = this.renderView(
|
|
5136
|
+
view,
|
|
5137
|
+
stack.enter(value, binds, false, itemPath, itemBase !== null)
|
|
5138
|
+
);
|
|
4966
5139
|
if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
|
|
4967
5140
|
this.cache.set(cachePath, cacheKey, dom);
|
|
4968
5141
|
}
|
|
@@ -5074,6 +5247,7 @@ export {
|
|
|
5074
5247
|
html,
|
|
5075
5248
|
injectCss,
|
|
5076
5249
|
macro,
|
|
5250
|
+
path,
|
|
5077
5251
|
phaseOps,
|
|
5078
5252
|
resolveArgs,
|
|
5079
5253
|
rootDispatcher,
|