tutuca 0.13.3 → 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 +572 -379
- package/dist/tutuca-dev.ext.js +605 -409
- package/dist/tutuca-dev.js +616 -420
- package/dist/tutuca-dev.min.js +4 -4
- package/dist/tutuca-extra.ext.js +588 -374
- package/dist/tutuca-extra.js +595 -381
- package/dist/tutuca-extra.min.js +3 -3
- package/dist/tutuca.ext.js +588 -374
- package/dist/tutuca.js +595 -381
- 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 +1 -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 +588 -374
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;
|
|
@@ -2379,13 +2464,16 @@ function h(tagName, properties, children, namespace) {
|
|
|
2379
2464
|
}
|
|
2380
2465
|
|
|
2381
2466
|
// src/anode.js
|
|
2382
|
-
function
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
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];
|
|
2389
2477
|
}
|
|
2390
2478
|
var BaseNode = class {
|
|
2391
2479
|
render(_stack, _rx) {
|
|
@@ -2707,33 +2795,31 @@ var RenderViewId = class extends ANode {
|
|
|
2707
2795
|
setDataAttr(_key, _val) {
|
|
2708
2796
|
}
|
|
2709
2797
|
};
|
|
2710
|
-
function dynRenderStep(comp, name, key) {
|
|
2711
|
-
const p = resolveDynProducer(comp, name);
|
|
2712
|
-
if (!p) return null;
|
|
2713
|
-
return key === void 0 ? new DynStep(p.producerCompId, p.producerSteps) : new DynEachStep(p.producerCompId, p.producerSteps, key);
|
|
2714
|
-
}
|
|
2715
2798
|
var RenderNode = class extends RenderViewId {
|
|
2716
2799
|
render(stack, rx) {
|
|
2717
|
-
const
|
|
2718
|
-
|
|
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);
|
|
2719
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.
|
|
2720
2806
|
toPathStep(ctx) {
|
|
2721
|
-
if (this.val instanceof DynVal) return
|
|
2807
|
+
if (this.val instanceof DynVal) return null;
|
|
2722
2808
|
return super.toPathStep(ctx);
|
|
2723
2809
|
}
|
|
2724
2810
|
};
|
|
2725
2811
|
var RenderItNode = class extends RenderViewId {
|
|
2726
2812
|
render(stack, rx) {
|
|
2727
|
-
const
|
|
2728
|
-
|
|
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);
|
|
2729
2816
|
}
|
|
2730
2817
|
toPathStep(ctx) {
|
|
2731
2818
|
const next = ctx.next();
|
|
2732
2819
|
if (next === null) return null;
|
|
2733
2820
|
const nextNode = next.resolveNode();
|
|
2734
2821
|
if (nextNode instanceof EachNode && next.hasKey) {
|
|
2735
|
-
if (nextNode.val instanceof DynVal)
|
|
2736
|
-
return dynRenderStep(ctx.comp, nextNode.val.name, next.key);
|
|
2822
|
+
if (nextNode.val instanceof DynVal) return null;
|
|
2737
2823
|
return new EachRenderItStep(nextNode.val.name, next.key);
|
|
2738
2824
|
}
|
|
2739
2825
|
return null;
|
|
@@ -2835,11 +2921,19 @@ var EachNode = class extends WrapperNode {
|
|
|
2835
2921
|
this.iterInfo = new IterInfo(val, null, null, null);
|
|
2836
2922
|
}
|
|
2837
2923
|
render(stack, rx) {
|
|
2838
|
-
return rx.renderEachWhen(stack, this
|
|
2924
|
+
return rx.renderEachWhen(stack, this);
|
|
2839
2925
|
}
|
|
2840
2926
|
toPathStep(ctx) {
|
|
2841
2927
|
return ctx.hasKey ? new EachBindStep(this.iterInfo, ctx.key) : null;
|
|
2842
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
|
+
}
|
|
2843
2937
|
static register = true;
|
|
2844
2938
|
};
|
|
2845
2939
|
var IterInfo = class {
|
|
@@ -3100,6 +3194,215 @@ function compileModifiers(eventName, names) {
|
|
|
3100
3194
|
};
|
|
3101
3195
|
}
|
|
3102
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
|
+
|
|
3103
3406
|
// src/components.js
|
|
3104
3407
|
var COMPONENT = /* @__PURE__ */ Symbol.for("tutuca.component");
|
|
3105
3408
|
var Components = class {
|
|
@@ -3138,12 +3441,14 @@ var ComponentStack = class _ComponentStack {
|
|
|
3138
3441
|
this.byName = {};
|
|
3139
3442
|
this.intentsByName = {};
|
|
3140
3443
|
this.macros = {};
|
|
3444
|
+
this.paths = {};
|
|
3141
3445
|
}
|
|
3142
3446
|
enter() {
|
|
3143
3447
|
return new _ComponentStack(this.comps, this);
|
|
3144
3448
|
}
|
|
3145
3449
|
registerComponents(comps, opts) {
|
|
3146
|
-
const { aliases = {} } = opts ?? {};
|
|
3450
|
+
const { aliases = {}, paths } = opts ?? {};
|
|
3451
|
+
if (paths) this.registerPaths(paths);
|
|
3147
3452
|
for (let i = 0; i < comps.length; i++) {
|
|
3148
3453
|
const Comp = comps[i];
|
|
3149
3454
|
Comp[COMPONENT].scope = this.enter();
|
|
@@ -3157,6 +3462,27 @@ var ComponentStack = class _ComponentStack {
|
|
|
3157
3462
|
else console.warn("alias", alias, "to inexistent component", aliases[alias]);
|
|
3158
3463
|
}
|
|
3159
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
|
+
}
|
|
3160
3486
|
registerMacros(macros) {
|
|
3161
3487
|
for (const key in macros) {
|
|
3162
3488
|
const lower = key.toLowerCase();
|
|
@@ -3188,17 +3514,16 @@ var ComponentStack = class _ComponentStack {
|
|
|
3188
3514
|
lookupComponent(name) {
|
|
3189
3515
|
return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
|
|
3190
3516
|
}
|
|
3191
|
-
//
|
|
3192
|
-
// names
|
|
3193
|
-
//
|
|
3194
|
-
//
|
|
3195
|
-
//
|
|
3196
|
-
|
|
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) {
|
|
3197
3523
|
for (const compName in this.byName) {
|
|
3198
|
-
|
|
3199
|
-
if (Comp.provide?.[name] !== void 0) return Comp;
|
|
3524
|
+
if (this.byName[compName].provide?.[name] !== void 0) return true;
|
|
3200
3525
|
}
|
|
3201
|
-
return this.parent?.
|
|
3526
|
+
return this.parent?.hasProvider(name) ?? false;
|
|
3202
3527
|
}
|
|
3203
3528
|
lookupMacro(name) {
|
|
3204
3529
|
return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
|
|
@@ -3215,10 +3540,6 @@ var LookupInfo = class {
|
|
|
3215
3540
|
}
|
|
3216
3541
|
};
|
|
3217
3542
|
var isString = (v) => typeof v === "string";
|
|
3218
|
-
var isTypeName = (s) => {
|
|
3219
|
-
const c = s.charCodeAt(0);
|
|
3220
|
-
return c >= 65 && c <= 90;
|
|
3221
|
-
};
|
|
3222
3543
|
var _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
|
|
3223
3544
|
var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
|
|
3224
3545
|
var _compId = 0;
|
|
@@ -3291,160 +3612,6 @@ var Component = class {
|
|
|
3291
3612
|
}
|
|
3292
3613
|
};
|
|
3293
3614
|
|
|
3294
|
-
// src/stack.js
|
|
3295
|
-
var STOP = /* @__PURE__ */ Symbol("STOP");
|
|
3296
|
-
var NEXT = /* @__PURE__ */ Symbol("NEXT");
|
|
3297
|
-
var DEFAULT_ROUTE = ["dyn", "lex"];
|
|
3298
|
-
function routeLookup(route, lex, dyn) {
|
|
3299
|
-
for (let i = 0; i < route.length; i++) {
|
|
3300
|
-
const leg = route[i];
|
|
3301
|
-
if (leg === "dyn") {
|
|
3302
|
-
const v = dyn();
|
|
3303
|
-
if (v != null) return v;
|
|
3304
|
-
} else if (leg === "lex") {
|
|
3305
|
-
const v = lex();
|
|
3306
|
-
if (v != null) return v;
|
|
3307
|
-
} else {
|
|
3308
|
-
console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
|
|
3309
|
-
}
|
|
3310
|
-
}
|
|
3311
|
-
return null;
|
|
3312
|
-
}
|
|
3313
|
-
function lookup(chain, name, dv = null) {
|
|
3314
|
-
let n = chain;
|
|
3315
|
-
while (n !== null) {
|
|
3316
|
-
const r = n[0].lookup(name);
|
|
3317
|
-
if (r === STOP) return dv;
|
|
3318
|
-
if (r !== NEXT) return r;
|
|
3319
|
-
n = n[1];
|
|
3320
|
-
}
|
|
3321
|
-
return dv;
|
|
3322
|
-
}
|
|
3323
|
-
var BindFrame = class {
|
|
3324
|
-
constructor(it, binds, isFrame) {
|
|
3325
|
-
this.it = it;
|
|
3326
|
-
this.binds = binds;
|
|
3327
|
-
this.isFrame = isFrame;
|
|
3328
|
-
}
|
|
3329
|
-
lookup(name) {
|
|
3330
|
-
const v = this.binds[name];
|
|
3331
|
-
return v === void 0 ? this.isFrame ? STOP : NEXT : v;
|
|
3332
|
-
}
|
|
3333
|
-
};
|
|
3334
|
-
var ObjectFrame = class {
|
|
3335
|
-
constructor(binds) {
|
|
3336
|
-
this.binds = binds;
|
|
3337
|
-
}
|
|
3338
|
-
lookup(key) {
|
|
3339
|
-
const v = this.binds[key];
|
|
3340
|
-
return v === void 0 ? NEXT : v;
|
|
3341
|
-
}
|
|
3342
|
-
};
|
|
3343
|
-
function computeViewsId(views) {
|
|
3344
|
-
let s = "";
|
|
3345
|
-
let n = views;
|
|
3346
|
-
while (n !== null) {
|
|
3347
|
-
s += n[0];
|
|
3348
|
-
n = n[1];
|
|
3349
|
-
}
|
|
3350
|
-
return s === "main" ? "" : s;
|
|
3351
|
-
}
|
|
3352
|
-
var Stack = class _Stack {
|
|
3353
|
-
constructor(comps, it, binds, dynBinds, views, viewsId, ctx = null) {
|
|
3354
|
-
this.comps = comps;
|
|
3355
|
-
this.it = it;
|
|
3356
|
-
this.binds = binds;
|
|
3357
|
-
this.dynBinds = dynBinds;
|
|
3358
|
-
this.views = views;
|
|
3359
|
-
this.viewsId = viewsId;
|
|
3360
|
-
this.ctx = ctx;
|
|
3361
|
-
}
|
|
3362
|
-
// Evaluate every provide the entered component publishes and push them as one
|
|
3363
|
-
// dynBinds frame, keyed by NAME. Published types go in the same frame: a type name
|
|
3364
|
-
// starts A-Z and a value name does not, so the two namespaces cannot collide and
|
|
3365
|
-
// nearest-ancestor-wins falls out of frame order for both. No-op with no provides.
|
|
3366
|
-
_pushProvides() {
|
|
3367
|
-
const comp = this.comps.getCompFor(this.it);
|
|
3368
|
-
if (comp == null) return this;
|
|
3369
|
-
const { provide, provideType } = comp;
|
|
3370
|
-
const dynObj = {};
|
|
3371
|
-
let has2 = false;
|
|
3372
|
-
for (const k in provide) {
|
|
3373
|
-
dynObj[k] = provide[k].val.eval(this);
|
|
3374
|
-
has2 = true;
|
|
3375
|
-
}
|
|
3376
|
-
for (const k in provideType) {
|
|
3377
|
-
dynObj[k] = provideType[k];
|
|
3378
|
-
has2 = true;
|
|
3379
|
-
}
|
|
3380
|
-
if (!has2) return this;
|
|
3381
|
-
const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
|
|
3382
|
-
const { comps, it, binds, views, viewsId, ctx } = this;
|
|
3383
|
-
return new _Stack(comps, it, binds, newDynBinds, views, viewsId, ctx);
|
|
3384
|
-
}
|
|
3385
|
-
static root(comps, it, ctx) {
|
|
3386
|
-
const binds = [new BindFrame(it, {}, true), null];
|
|
3387
|
-
const dynBinds = [new ObjectFrame({}), null];
|
|
3388
|
-
const views = ["main", null];
|
|
3389
|
-
return new _Stack(comps, it, binds, dynBinds, views, "", ctx)._pushProvides();
|
|
3390
|
-
}
|
|
3391
|
-
enter(it, bindings = {}, isFrame = true) {
|
|
3392
|
-
const { comps, binds, dynBinds, views, viewsId, ctx } = this;
|
|
3393
|
-
const newBinds = [new BindFrame(it, bindings, isFrame), binds];
|
|
3394
|
-
const stack = new _Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx);
|
|
3395
|
-
return isFrame ? stack._pushProvides() : stack;
|
|
3396
|
-
}
|
|
3397
|
-
pushViewName(name) {
|
|
3398
|
-
const { comps, it, binds, dynBinds, views, ctx } = this;
|
|
3399
|
-
const newViews = [name, views];
|
|
3400
|
-
return new _Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
|
|
3401
|
-
}
|
|
3402
|
-
// Published types are stable per scope and would only churn the render cache, so
|
|
3403
|
-
// the cache key covers values alone.
|
|
3404
|
-
_pushDynBindValuesToArray(arr, comp) {
|
|
3405
|
-
for (const k in comp.provide) arr.push(this.lookupDynamic(k));
|
|
3406
|
-
for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
|
|
3407
|
-
}
|
|
3408
|
-
// `*name`: the nearest binding above (including this component's own provides,
|
|
3409
|
-
// pushed on entering it), else this component's declared default, else null.
|
|
3410
|
-
lookupDynamic(name) {
|
|
3411
|
-
const v = lookup(this.dynBinds, name);
|
|
3412
|
-
if (v != null) return v;
|
|
3413
|
-
const comp = this.comps.getCompFor(this.it);
|
|
3414
|
-
return comp?.lookup[name]?.val?.eval(this) ?? null;
|
|
3415
|
-
}
|
|
3416
|
-
lookupBind(name) {
|
|
3417
|
-
return lookup(this.binds, name);
|
|
3418
|
-
}
|
|
3419
|
-
lookupFieldRaw(name) {
|
|
3420
|
-
return this.it[name] ?? null;
|
|
3421
|
-
}
|
|
3422
|
-
lookupMethod(name) {
|
|
3423
|
-
const fn = this.it[name];
|
|
3424
|
-
return fn instanceof Function ? fn.call(this.it) : null;
|
|
3425
|
-
}
|
|
3426
|
-
// The dispatched DOM event / drag info, read only by EventMemberVal's
|
|
3427
|
-
// `e.<member>` handler args. Null outside a live event transaction.
|
|
3428
|
-
lookupEvent() {
|
|
3429
|
-
return this.ctx?.event ?? null;
|
|
3430
|
-
}
|
|
3431
|
-
lookupDragInfo() {
|
|
3432
|
-
return this.ctx?.dragInfo ?? null;
|
|
3433
|
-
}
|
|
3434
|
-
getHandlerFor(name, key) {
|
|
3435
|
-
return this.comps.getHandlerFor(this.it, name, key);
|
|
3436
|
-
}
|
|
3437
|
-
lookupBestView(views, defaultViewName) {
|
|
3438
|
-
let n = this.views;
|
|
3439
|
-
while (n !== null) {
|
|
3440
|
-
const view = views[n[0]];
|
|
3441
|
-
if (view !== void 0) return view;
|
|
3442
|
-
n = n[1];
|
|
3443
|
-
}
|
|
3444
|
-
return views[defaultViewName];
|
|
3445
|
-
}
|
|
3446
|
-
};
|
|
3447
|
-
|
|
3448
3615
|
// src/oo.js
|
|
3449
3616
|
var BAD_VALUE = /* @__PURE__ */ Symbol("BadValue");
|
|
3450
3617
|
var nullCoercer = (v) => v;
|
|
@@ -3790,9 +3957,9 @@ var Transactor = class {
|
|
|
3790
3957
|
// `.a[.selId]` render target reconstructed from a DOM event) against the root the
|
|
3791
3958
|
// handler read, so pathKeys carries concrete keys instead of dropping the dynamic
|
|
3792
3959
|
// step. No-op when nobody is observing.
|
|
3793
|
-
_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 }) {
|
|
3794
3961
|
if (this._observers.length === 0) return;
|
|
3795
|
-
const pinned =
|
|
3962
|
+
const pinned = path2.pinKeys(root);
|
|
3796
3963
|
this._emit({
|
|
3797
3964
|
kind,
|
|
3798
3965
|
name,
|
|
@@ -3843,18 +4010,20 @@ var Transactor = class {
|
|
|
3843
4010
|
// intent's answerPath is: a reply must reach the sender that asked even if a key
|
|
3844
4011
|
// moved while the message was in flight. Null when nobody is waiting — a host
|
|
3845
4012
|
// sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
|
|
3846
|
-
pushSend(
|
|
3847
|
-
const t = new SendEvent(
|
|
3848
|
-
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);
|
|
3849
4018
|
this.pushTransaction(t);
|
|
3850
4019
|
return this._link(t, parent);
|
|
3851
4020
|
}
|
|
3852
4021
|
// Raise an intent: a job the sender did not address, walked along a route until
|
|
3853
4022
|
// something answers. `opts.route` is a list of legs (see DEFAULT_ROUTE) and
|
|
3854
4023
|
// `opts.livePath` opts out of pinning the answer's destination keys.
|
|
3855
|
-
pushIntent(
|
|
4024
|
+
pushIntent(path2, name, args = [], opts = {}, parent = null) {
|
|
3856
4025
|
const release = parent ? parent.completion.track() : null;
|
|
3857
|
-
const walk = new IntentWalk(this,
|
|
4026
|
+
const walk = new IntentWalk(this, path2, name, args, opts, parent, release);
|
|
3858
4027
|
walk.advance();
|
|
3859
4028
|
return walk;
|
|
3860
4029
|
}
|
|
@@ -3888,16 +4057,17 @@ var Transactor = class {
|
|
|
3888
4057
|
transaction._completion?.releaseSelf();
|
|
3889
4058
|
}
|
|
3890
4059
|
}
|
|
3891
|
-
transactInputNow(
|
|
3892
|
-
this.transact(new InputEvent(
|
|
4060
|
+
transactInputNow(path2, event, eventHandler, dragInfo) {
|
|
4061
|
+
this.transact(new InputEvent(path2, event, eventHandler, this, dragInfo));
|
|
3893
4062
|
}
|
|
3894
4063
|
};
|
|
3895
4064
|
function nullHandler() {
|
|
3896
4065
|
return this;
|
|
3897
4066
|
}
|
|
3898
4067
|
var Transaction = class {
|
|
3899
|
-
constructor(
|
|
3900
|
-
this.path =
|
|
4068
|
+
constructor(path2, transactor, parentTransaction = null) {
|
|
4069
|
+
this.path = path2;
|
|
4070
|
+
this.txnPath = null;
|
|
3901
4071
|
this.transactor = transactor;
|
|
3902
4072
|
this.parentTransaction = parentTransaction;
|
|
3903
4073
|
this._completion = null;
|
|
@@ -3946,9 +4116,11 @@ var Transaction = class {
|
|
|
3946
4116
|
getHandlerAndArgs(_root, _instance, _comps) {
|
|
3947
4117
|
return null;
|
|
3948
4118
|
}
|
|
3949
|
-
// The path used to apply the mutation
|
|
3950
|
-
//
|
|
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).
|
|
3951
4122
|
getTransactionPath() {
|
|
4123
|
+
if (this.txnPath !== null) return this.txnPath;
|
|
3952
4124
|
return this.path.toTransactionPath().compact();
|
|
3953
4125
|
}
|
|
3954
4126
|
run(curRoot, comps) {
|
|
@@ -3966,15 +4138,16 @@ var Transaction = class {
|
|
|
3966
4138
|
}
|
|
3967
4139
|
};
|
|
3968
4140
|
var InputEvent = class extends Transaction {
|
|
3969
|
-
constructor(
|
|
3970
|
-
super(
|
|
4141
|
+
constructor(path2, e, handler, transactor, dragInfo) {
|
|
4142
|
+
super(path2, transactor);
|
|
3971
4143
|
this.e = e;
|
|
3972
4144
|
this.handler = handler;
|
|
3973
4145
|
this.dragInfo = dragInfo;
|
|
3974
4146
|
this._dispatchPath = null;
|
|
3975
4147
|
}
|
|
3976
|
-
// Frame steps removed,
|
|
3977
|
-
//
|
|
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`.
|
|
3978
4151
|
get dispatchPath() {
|
|
3979
4152
|
this._dispatchPath ??= this.path.compact();
|
|
3980
4153
|
return this._dispatchPath;
|
|
@@ -4009,11 +4182,11 @@ var InputEvent = class extends Transaction {
|
|
|
4009
4182
|
this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
|
|
4010
4183
|
}
|
|
4011
4184
|
getHandlerAndArgs(root, _instance, comps) {
|
|
4012
|
-
const stack = this.path.
|
|
4185
|
+
const stack = this.path.buildStack(Stack.root(comps, root, this));
|
|
4013
4186
|
const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
|
|
4014
4187
|
this._handlerArgs = [...args];
|
|
4015
|
-
const
|
|
4016
|
-
args.push(new EventContext(
|
|
4188
|
+
const path2 = this.dispatchPath;
|
|
4189
|
+
args.push(new EventContext(path2, this.transactor, this));
|
|
4017
4190
|
return [handler, args];
|
|
4018
4191
|
}
|
|
4019
4192
|
// The dispatched DOM event, read only through `e.<member>` handler args
|
|
@@ -4024,11 +4197,11 @@ var InputEvent = class extends Transaction {
|
|
|
4024
4197
|
}
|
|
4025
4198
|
};
|
|
4026
4199
|
var NameArgsTransaction = class extends Transaction {
|
|
4027
|
-
constructor(
|
|
4028
|
-
super(
|
|
4200
|
+
constructor(path2, transactor, name, args, parentTransaction) {
|
|
4201
|
+
super(path2, transactor, parentTransaction);
|
|
4029
4202
|
this.name = name;
|
|
4030
4203
|
this.args = args;
|
|
4031
|
-
this.targetPath =
|
|
4204
|
+
this.targetPath = path2;
|
|
4032
4205
|
}
|
|
4033
4206
|
handlerProp = null;
|
|
4034
4207
|
// NameArgs verbs map their handler bucket straight to the observed kind:
|
|
@@ -4085,8 +4258,8 @@ var SendEvent = class extends NameArgsTransaction {
|
|
|
4085
4258
|
};
|
|
4086
4259
|
var IntentEvent = class extends NameArgsTransaction {
|
|
4087
4260
|
handlerProp = "intent";
|
|
4088
|
-
constructor(
|
|
4089
|
-
super(
|
|
4261
|
+
constructor(path2, transactor, walk) {
|
|
4262
|
+
super(path2, transactor, walk.name, walk.args, walk.parent);
|
|
4090
4263
|
this.walk = walk;
|
|
4091
4264
|
this.targetPath = walk.origin;
|
|
4092
4265
|
}
|
|
@@ -4113,17 +4286,17 @@ var PASS = /* @__PURE__ */ Symbol.for("tutuca.intent.pass");
|
|
|
4113
4286
|
var REFUSAL_RING_CAP = 200;
|
|
4114
4287
|
var INTENT_DEPTH = 64;
|
|
4115
4288
|
var IntentWalk = class {
|
|
4116
|
-
constructor(transactor,
|
|
4289
|
+
constructor(transactor, path2, name, args, opts, parent, release) {
|
|
4117
4290
|
this.transactor = transactor;
|
|
4118
4291
|
this.name = name;
|
|
4119
4292
|
this.args = args;
|
|
4120
4293
|
this.route = opts?.route ?? DEFAULT_ROUTE;
|
|
4121
4294
|
this.parent = parent;
|
|
4122
4295
|
this.release = release;
|
|
4123
|
-
this.origin =
|
|
4124
|
-
this.answerPath = opts?.livePath ? null :
|
|
4296
|
+
this.origin = path2;
|
|
4297
|
+
this.answerPath = opts?.livePath ? null : path2.toTransactionPath().pinKeys(transactor.state.val);
|
|
4125
4298
|
this.legIndex = 0;
|
|
4126
|
-
this.dynAt =
|
|
4299
|
+
this.dynAt = path2;
|
|
4127
4300
|
this.hops = 0;
|
|
4128
4301
|
this.ended = false;
|
|
4129
4302
|
}
|
|
@@ -4135,7 +4308,7 @@ var IntentWalk = class {
|
|
|
4135
4308
|
while (this.legIndex < this.route.length) {
|
|
4136
4309
|
const leg = this.route[this.legIndex];
|
|
4137
4310
|
if (leg === "dyn") {
|
|
4138
|
-
if (this.dynAt.
|
|
4311
|
+
if (!this.dynAt.canPop()) {
|
|
4139
4312
|
this.legIndex++;
|
|
4140
4313
|
continue;
|
|
4141
4314
|
}
|
|
@@ -4232,8 +4405,8 @@ var IntentWalk = class {
|
|
|
4232
4405
|
if (this.ended) return;
|
|
4233
4406
|
this.ended = true;
|
|
4234
4407
|
if (name === null) return this.release?.();
|
|
4235
|
-
const
|
|
4236
|
-
|
|
4408
|
+
const t = new SendEvent(this.origin, this.transactor, name, args, this.parent);
|
|
4409
|
+
t.txnPath = this.answerPath;
|
|
4237
4410
|
t._isAnswer = true;
|
|
4238
4411
|
this.transactor.pushTransaction(t);
|
|
4239
4412
|
if (this.release) t.completion.whenSubtreeSettled().then(this.release);
|
|
@@ -4299,8 +4472,8 @@ var Completion = class {
|
|
|
4299
4472
|
}
|
|
4300
4473
|
};
|
|
4301
4474
|
var Dispatcher = class {
|
|
4302
|
-
constructor(
|
|
4303
|
-
this.path =
|
|
4475
|
+
constructor(path2, transactor, parentTransaction, root = transactor.state.val) {
|
|
4476
|
+
this.path = path2;
|
|
4304
4477
|
this.transactor = transactor;
|
|
4305
4478
|
this.parent = parentTransaction;
|
|
4306
4479
|
this.root = root;
|
|
@@ -4328,7 +4501,9 @@ var Dispatcher = class {
|
|
|
4328
4501
|
// replayed; provides are pushed on every component frame either way, so a provide
|
|
4329
4502
|
// that reads a loop binding is the one case this cannot reproduce faithfully.
|
|
4330
4503
|
_stack() {
|
|
4331
|
-
this._stackMemo ??= this.path.
|
|
4504
|
+
this._stackMemo ??= this.path.buildStack(
|
|
4505
|
+
Stack.root(this.transactor.comps, this.root, this.parent)
|
|
4506
|
+
);
|
|
4332
4507
|
return this._stackMemo;
|
|
4333
4508
|
}
|
|
4334
4509
|
// Resolve a name the way the renderer would. `opts.route` takes the same legs in
|
|
@@ -4342,14 +4517,19 @@ var Dispatcher = class {
|
|
|
4342
4517
|
);
|
|
4343
4518
|
}
|
|
4344
4519
|
// The `lex` leg without a Stack: the scope of the component whose handler is
|
|
4345
|
-
// 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.
|
|
4346
4523
|
_lookupLex(name) {
|
|
4347
4524
|
let Comp = null;
|
|
4348
4525
|
this.walkPath((c) => {
|
|
4349
4526
|
Comp = c;
|
|
4350
4527
|
return false;
|
|
4351
4528
|
});
|
|
4352
|
-
|
|
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;
|
|
4353
4533
|
}
|
|
4354
4534
|
// A component lookup is a value lookup constrained to a component. The `lex` leg
|
|
4355
4535
|
// can only ever answer with one; the `dyn` leg reads a binding an ancestor
|
|
@@ -4371,8 +4551,8 @@ var Dispatcher = class {
|
|
|
4371
4551
|
send(name, args) {
|
|
4372
4552
|
return this.sendAtPath(this.path, name, args);
|
|
4373
4553
|
}
|
|
4374
|
-
sendAtPath(
|
|
4375
|
-
return this.transactor.pushSend(
|
|
4554
|
+
sendAtPath(path2, name, args) {
|
|
4555
|
+
return this.transactor.pushSend(path2, name, args, this.parent, this.path);
|
|
4376
4556
|
}
|
|
4377
4557
|
// An intent is ROUTED: it names a job and walks until something answers. The verb
|
|
4378
4558
|
// does not decide which scope answers — `opts.route` does, written here at the call
|
|
@@ -4380,8 +4560,8 @@ var Dispatcher = class {
|
|
|
4380
4560
|
intent(name, args, opts) {
|
|
4381
4561
|
return this.intentAtPath(this.path, name, args, opts);
|
|
4382
4562
|
}
|
|
4383
|
-
intentAtPath(
|
|
4384
|
-
return this.transactor.pushIntent(
|
|
4563
|
+
intentAtPath(path2, name, args, opts) {
|
|
4564
|
+
return this.transactor.pushIntent(path2, name, args, opts, this.parent);
|
|
4385
4565
|
}
|
|
4386
4566
|
};
|
|
4387
4567
|
var EventContext = class extends Dispatcher {
|
|
@@ -4410,7 +4590,14 @@ var EventContext = class extends Dispatcher {
|
|
|
4410
4590
|
this.transactor.refuse("NO_SENDER", { name });
|
|
4411
4591
|
return null;
|
|
4412
4592
|
}
|
|
4413
|
-
return this.
|
|
4593
|
+
return this.transactor.pushSend(
|
|
4594
|
+
origin,
|
|
4595
|
+
name,
|
|
4596
|
+
args,
|
|
4597
|
+
this.parent,
|
|
4598
|
+
this.path,
|
|
4599
|
+
this.parent.originPinned
|
|
4600
|
+
);
|
|
4414
4601
|
}
|
|
4415
4602
|
// End the walk answering nothing — "served, and no answer".
|
|
4416
4603
|
stop() {
|
|
@@ -4442,7 +4629,7 @@ var PathChanges = class extends PathBuilder {
|
|
|
4442
4629
|
}
|
|
4443
4630
|
};
|
|
4444
4631
|
function rootDispatcher(transactor) {
|
|
4445
|
-
return new Dispatcher(new
|
|
4632
|
+
return new Dispatcher(new DispatchPath(), transactor, null);
|
|
4446
4633
|
}
|
|
4447
4634
|
|
|
4448
4635
|
// src/app.js
|
|
@@ -4483,7 +4670,7 @@ var App = class {
|
|
|
4483
4670
|
const { type } = e;
|
|
4484
4671
|
const isDrag = type === "dragover" || type === "dragstart" || type === "dragend" || type === "drop";
|
|
4485
4672
|
const { rootNode: root, maxEventNodeDepth: maxDepth, comps, transactor } = this;
|
|
4486
|
-
const [
|
|
4673
|
+
const [path2, handlers] = DispatchPath.fromNodeAndEventName(
|
|
4487
4674
|
e.target,
|
|
4488
4675
|
type,
|
|
4489
4676
|
root,
|
|
@@ -4491,9 +4678,9 @@ var App = class {
|
|
|
4491
4678
|
comps,
|
|
4492
4679
|
!isDrag
|
|
4493
4680
|
);
|
|
4494
|
-
if (isDrag) this._handleDragEvent(e, type,
|
|
4495
|
-
if (
|
|
4496
|
-
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);
|
|
4497
4684
|
}
|
|
4498
4685
|
_handleTouchEvent(e) {
|
|
4499
4686
|
const { type } = e;
|
|
@@ -4536,7 +4723,7 @@ var App = class {
|
|
|
4536
4723
|
this._touch = null;
|
|
4537
4724
|
}
|
|
4538
4725
|
}
|
|
4539
|
-
_handleDragEvent(e, type,
|
|
4726
|
+
_handleDragEvent(e, type, path2) {
|
|
4540
4727
|
if (type === "dragover") {
|
|
4541
4728
|
const dropTarget = getClosestDropTarget(e.target, this.rootNode, Infinity);
|
|
4542
4729
|
if (dropTarget !== null) {
|
|
@@ -4548,10 +4735,10 @@ var App = class {
|
|
|
4548
4735
|
} else if (type === "dragstart") {
|
|
4549
4736
|
e.target.dataset.dragging = 1;
|
|
4550
4737
|
const rootValue = this.state.val;
|
|
4551
|
-
const txnPath =
|
|
4738
|
+
const txnPath = path2.compact().toTransactionPath();
|
|
4552
4739
|
const value = txnPath.lookup(rootValue);
|
|
4553
4740
|
const dragType = e.target.dataset.dragtype ?? "?";
|
|
4554
|
-
const stack =
|
|
4741
|
+
const stack = path2.buildStack(this.makeStack(rootValue));
|
|
4555
4742
|
this.dragInfo = new DragInfo(stack, value, dragType, e.target);
|
|
4556
4743
|
} else if (type === "drop") {
|
|
4557
4744
|
e.preventDefault();
|
|
@@ -4626,7 +4813,7 @@ var App = class {
|
|
|
4626
4813
|
this.rootNode.removeEventListener(name, this, listenerOpts(name));
|
|
4627
4814
|
}
|
|
4628
4815
|
sendAtRoot(name, args) {
|
|
4629
|
-
this.transactor.pushSend(new
|
|
4816
|
+
this.transactor.pushSend(new DispatchPath(), name, args);
|
|
4630
4817
|
}
|
|
4631
4818
|
registerComponents(comps, opts) {
|
|
4632
4819
|
const scope = this.compStack.enter();
|
|
@@ -4844,7 +5031,20 @@ var WeakMapDomCache = class {
|
|
|
4844
5031
|
};
|
|
4845
5032
|
|
|
4846
5033
|
// src/renderer.js
|
|
4847
|
-
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
|
+
}
|
|
4848
5048
|
var Renderer = class {
|
|
4849
5049
|
constructor(comps) {
|
|
4850
5050
|
this.comps = comps;
|
|
@@ -4881,17 +5081,17 @@ var Renderer = class {
|
|
|
4881
5081
|
if (comp === null) return null;
|
|
4882
5082
|
return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
|
|
4883
5083
|
}
|
|
4884
|
-
renderIt(stack, node, key, viewName) {
|
|
5084
|
+
renderIt(stack, node, key, viewName, base = null) {
|
|
4885
5085
|
const comp = this.comps.getCompFor(stack.it);
|
|
4886
|
-
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;
|
|
4887
5087
|
}
|
|
4888
5088
|
// `node` is the parse node of the render site (`<x render>` / `render-it` /
|
|
4889
5089
|
// `render-each`, or the view's root anode for the app root). It keys the
|
|
4890
5090
|
// cache as a globally-unique object: node ids alone are unique only within a
|
|
4891
5091
|
// single view, so the same value rendered by two components (e.g. through a
|
|
4892
5092
|
// shared dynamic-var sequence) would otherwise collide in the cache.
|
|
4893
|
-
_rValComp(stack, val, comp, node, key, viewName) {
|
|
4894
|
-
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}`;
|
|
4895
5095
|
const cachePath = [node, val];
|
|
4896
5096
|
stack._pushDynBindValuesToArray(cachePath, comp);
|
|
4897
5097
|
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
@@ -4899,30 +5099,43 @@ var Renderer = class {
|
|
|
4899
5099
|
const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
|
|
4900
5100
|
const body = this.renderView(view, stack);
|
|
4901
5101
|
if (body == null) return null;
|
|
5102
|
+
const baseJson = base === null ? null : pathToJson(base);
|
|
4902
5103
|
const meta = this._renderMetadata({
|
|
4903
5104
|
$: "Comp",
|
|
4904
5105
|
nid: node?.nodeId ?? null,
|
|
4905
5106
|
cid: comp.id,
|
|
4906
|
-
vid: view.name
|
|
5107
|
+
vid: view.name,
|
|
5108
|
+
...baseJson === null ? null : { base: baseJson }
|
|
4907
5109
|
});
|
|
4908
|
-
const dom = new VFragment([
|
|
5110
|
+
const dom = new VFragment([
|
|
5111
|
+
meta,
|
|
5112
|
+
baseJson === null ? body : stampRenderBase(body, JSON.stringify(baseJson))
|
|
5113
|
+
]);
|
|
4909
5114
|
this.cache.set(cachePath, cacheKey, dom);
|
|
4910
5115
|
return dom;
|
|
4911
5116
|
}
|
|
4912
5117
|
pushEachEntry(r, nid, attrName, key, dom) {
|
|
4913
5118
|
r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
|
|
4914
5119
|
}
|
|
4915
|
-
renderEachWhen(stack,
|
|
5120
|
+
renderEachWhen(stack, each2) {
|
|
5121
|
+
const { iterInfo, node: view, nodeId: nid } = each2;
|
|
4916
5122
|
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
5123
|
+
const seqPath = iterInfo.val instanceof DynVal ? stack.lookupDynamicLocated(iterInfo.val.name)?.path ?? null : null;
|
|
4917
5124
|
const r = [];
|
|
4918
5125
|
const it = stack.it;
|
|
4919
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;
|
|
4920
5130
|
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
4921
|
-
const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
|
|
5131
|
+
const cacheKey = `${stack.viewsId ?? ""}${nid}${key}${itemPath.addressKey}`;
|
|
4922
5132
|
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
4923
5133
|
if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
4924
5134
|
else {
|
|
4925
|
-
const dom = this.renderView(
|
|
5135
|
+
const dom = this.renderView(
|
|
5136
|
+
view,
|
|
5137
|
+
stack.enter(value, binds, false, itemPath, itemBase !== null)
|
|
5138
|
+
);
|
|
4926
5139
|
if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
|
|
4927
5140
|
this.cache.set(cachePath, cacheKey, dom);
|
|
4928
5141
|
}
|
|
@@ -5034,6 +5247,7 @@ export {
|
|
|
5034
5247
|
html,
|
|
5035
5248
|
injectCss,
|
|
5036
5249
|
macro,
|
|
5250
|
+
path,
|
|
5037
5251
|
phaseOps,
|
|
5038
5252
|
resolveArgs,
|
|
5039
5253
|
rootDispatcher,
|