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.ext.js
CHANGED
|
@@ -76,8 +76,11 @@ var Step = class {
|
|
|
76
76
|
}
|
|
77
77
|
setDraftValue(_root, _v) {
|
|
78
78
|
}
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
// Re-enter this step while rebuilding a stack. `renderPath` is the dispatch
|
|
80
|
+
// position AFTER this step: a rebuilt frame must carry the same render path
|
|
81
|
+
// the renderer had there, or the provides it publishes would be located wrong.
|
|
82
|
+
enterFrame(stack, next, renderPath) {
|
|
83
|
+
return stack.enter(next, {}, true, renderPath);
|
|
81
84
|
}
|
|
82
85
|
toAbstractPathStep() {
|
|
83
86
|
return this;
|
|
@@ -102,8 +105,8 @@ var BindStep = class _BindStep extends Step {
|
|
|
102
105
|
lookup(v, _dval) {
|
|
103
106
|
return v;
|
|
104
107
|
}
|
|
105
|
-
enterFrame(stack, next) {
|
|
106
|
-
return stack.enter(next, { ...this.binds }, false);
|
|
108
|
+
enterFrame(stack, next, renderPath) {
|
|
109
|
+
return stack.enter(next, { ...this.binds }, false, renderPath);
|
|
107
110
|
}
|
|
108
111
|
withIndex(i) {
|
|
109
112
|
return new _BindStep({ ...this.binds, key: i });
|
|
@@ -120,9 +123,9 @@ var ScopeBindStep = class _ScopeBindStep extends BindStep {
|
|
|
120
123
|
super(binds);
|
|
121
124
|
this.val = val;
|
|
122
125
|
}
|
|
123
|
-
enterFrame(stack, next) {
|
|
126
|
+
enterFrame(stack, next, renderPath) {
|
|
124
127
|
const dyn = this.val.evalAsHandler(stack)?.call(stack.it) ?? {};
|
|
125
|
-
return stack.enter(next, { ...this.binds, ...dyn }, false);
|
|
128
|
+
return stack.enter(next, { ...this.binds, ...dyn }, false, renderPath);
|
|
126
129
|
}
|
|
127
130
|
withIndex(i) {
|
|
128
131
|
return new _ScopeBindStep(this.val, { ...this.binds, key: i });
|
|
@@ -165,8 +168,8 @@ var SeqStep = class extends Step {
|
|
|
165
168
|
const seq = readKey(root, this.field, null);
|
|
166
169
|
if (seq != null) writeSeqKey(seq, this.key, v);
|
|
167
170
|
}
|
|
168
|
-
enterFrame(stack, next) {
|
|
169
|
-
return stack.enter(next, { key: this.key }, true);
|
|
171
|
+
enterFrame(stack, next, renderPath) {
|
|
172
|
+
return stack.enter(next, { key: this.key }, true, renderPath);
|
|
170
173
|
}
|
|
171
174
|
toKey() {
|
|
172
175
|
return { field: this.field, key: this.key };
|
|
@@ -212,60 +215,52 @@ var EachBindStep = class extends Step {
|
|
|
212
215
|
}
|
|
213
216
|
// Replay the renderer's per-item binds (key, value + any @enrich-with binds)
|
|
214
217
|
// so a rebuilt stack matches the one @each rendered with.
|
|
215
|
-
enterFrame(stack, next) {
|
|
216
|
-
return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false);
|
|
218
|
+
enterFrame(stack, next, renderPath) {
|
|
219
|
+
return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false, renderPath);
|
|
217
220
|
}
|
|
218
221
|
toAbstractPathStep() {
|
|
219
222
|
return null;
|
|
220
223
|
}
|
|
221
224
|
};
|
|
222
225
|
var EachRenderItStep = class extends SeqStep {
|
|
223
|
-
enterFrame(stack, next) {
|
|
224
|
-
return stack.enter(next, { key: this.key, value: next }, false).enter(next, {}, true);
|
|
226
|
+
enterFrame(stack, next, renderPath) {
|
|
227
|
+
return stack.enter(next, { key: this.key, value: next }, false, renderPath).enter(next, {}, true, renderPath);
|
|
225
228
|
}
|
|
226
229
|
toAbstractPathStep() {
|
|
227
230
|
return new SeqStep(this.field, this.key);
|
|
228
231
|
}
|
|
229
232
|
};
|
|
230
|
-
function
|
|
231
|
-
|
|
233
|
+
function stepToJson(step) {
|
|
234
|
+
if (step instanceof SeqStep) return { f: step.field, k: step.key };
|
|
235
|
+
if (step instanceof FieldStep) return { f: step.field };
|
|
236
|
+
if (step instanceof SeqAccessStep) return { f: step.seqField, a: step.keyField };
|
|
237
|
+
return null;
|
|
232
238
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
warnRawDynStep("lookup", this);
|
|
246
|
-
return dval;
|
|
247
|
-
}
|
|
248
|
-
enterFrame(stack, _next) {
|
|
249
|
-
warnRawDynStep("enterFrame", this);
|
|
250
|
-
return stack;
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
var DynEachStep = class extends DynStep {
|
|
254
|
-
constructor(producerCompId, producerSteps, key) {
|
|
255
|
-
super(producerCompId, producerSteps);
|
|
256
|
-
this.key = key;
|
|
257
|
-
}
|
|
258
|
-
teleportSteps() {
|
|
259
|
-
const { producerSteps, key } = this;
|
|
260
|
-
if (producerSteps.length === 0) return producerSteps;
|
|
261
|
-
const last = producerSteps[producerSteps.length - 1];
|
|
262
|
-
if (!(last instanceof FieldStep)) {
|
|
263
|
-
console.warn("DynEachStep: seq-access dynamic cannot be iterated", this);
|
|
264
|
-
return producerSteps;
|
|
265
|
-
}
|
|
266
|
-
return producerSteps.slice(0, -1).concat(new SeqStep(last.field, key));
|
|
239
|
+
function stepFromJson(j) {
|
|
240
|
+
if (j == null || typeof j.f !== "string") return null;
|
|
241
|
+
if (j.k !== void 0) return new SeqStep(j.f, j.k);
|
|
242
|
+
if (j.a !== void 0) return new SeqAccessStep(j.f, j.a);
|
|
243
|
+
return new FieldStep(j.f);
|
|
244
|
+
}
|
|
245
|
+
function pathToJson(path2) {
|
|
246
|
+
const out = [];
|
|
247
|
+
for (const step of path2.steps) {
|
|
248
|
+
const j = stepToJson(step);
|
|
249
|
+
if (j === null) return null;
|
|
250
|
+
out.push(j);
|
|
267
251
|
}
|
|
268
|
-
|
|
252
|
+
return out;
|
|
253
|
+
}
|
|
254
|
+
function pathFromJson(j) {
|
|
255
|
+
if (!Array.isArray(j)) return null;
|
|
256
|
+
const steps = [];
|
|
257
|
+
for (const item of j) {
|
|
258
|
+
const step = stepFromJson(item);
|
|
259
|
+
if (step === null) return null;
|
|
260
|
+
steps.push(step);
|
|
261
|
+
}
|
|
262
|
+
return new Path(steps);
|
|
263
|
+
}
|
|
269
264
|
var Path = class _Path {
|
|
270
265
|
constructor(steps = []) {
|
|
271
266
|
this.steps = steps;
|
|
@@ -276,40 +271,13 @@ var Path = class _Path {
|
|
|
276
271
|
popStep() {
|
|
277
272
|
return new _Path(this.steps.slice(0, -1));
|
|
278
273
|
}
|
|
279
|
-
//
|
|
280
|
-
//
|
|
274
|
+
// Frame-only steps removed, one step per crossed component: `popStep` over the
|
|
275
|
+
// result bubbles through every component.
|
|
281
276
|
compact() {
|
|
282
277
|
const out = [];
|
|
283
278
|
for (const step of this.steps) {
|
|
284
279
|
const s = step.toAbstractPathStep();
|
|
285
|
-
if (s !== null)
|
|
286
|
-
if (s !== step) s._originCid = step._originCid;
|
|
287
|
-
out.push(s);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
return new _Path(out);
|
|
291
|
-
}
|
|
292
|
-
// The abstract path used to apply a transaction: every DynStep is teleported —
|
|
293
|
-
// the steps interior to its producer..consumer span are dropped and the
|
|
294
|
-
// producer's own path spliced in — so a mutation lands on the data's real
|
|
295
|
-
// location. A path with no DynStep is returned unchanged.
|
|
296
|
-
toTransactionPath() {
|
|
297
|
-
let hasDyn = false;
|
|
298
|
-
for (const step of this.steps)
|
|
299
|
-
if (step instanceof DynStep) {
|
|
300
|
-
hasDyn = true;
|
|
301
|
-
break;
|
|
302
|
-
}
|
|
303
|
-
if (!hasDyn) return this;
|
|
304
|
-
const out = [];
|
|
305
|
-
for (const step of this.steps) {
|
|
306
|
-
if (step instanceof DynStep) {
|
|
307
|
-
while (out.length > 0 && step.interiorCids.has(out[out.length - 1]._originCid)) out.pop();
|
|
308
|
-
for (const ts of step.teleportSteps()) {
|
|
309
|
-
ts._originCid = step.producerCompId;
|
|
310
|
-
out.push(ts);
|
|
311
|
-
}
|
|
312
|
-
} else out.push(step);
|
|
280
|
+
if (s !== null) out.push(s);
|
|
313
281
|
}
|
|
314
282
|
return new _Path(out);
|
|
315
283
|
}
|
|
@@ -317,7 +285,6 @@ var Path = class _Path {
|
|
|
317
285
|
// key as it is *now* so a later lookup/setValue lands on the same item even if the
|
|
318
286
|
// keyField changed meanwhile (e.g. the selected tab moved while an intent was in
|
|
319
287
|
// flight). Returns a new Path with those steps replaced; `this` if nothing pinned.
|
|
320
|
-
// Must be called on a transaction path (no DynSteps — call toTransactionPath first).
|
|
321
288
|
pinKeys(root) {
|
|
322
289
|
let curVal = root;
|
|
323
290
|
let out = null;
|
|
@@ -340,8 +307,8 @@ var Path = class _Path {
|
|
|
340
307
|
}
|
|
341
308
|
// The values entered along the path, root→leaf (root included): index 0 is `root`,
|
|
342
309
|
// the last entry is the leaf this path resolves to. Stops early at the first
|
|
343
|
-
// unresolvable step.
|
|
344
|
-
//
|
|
310
|
+
// unresolvable step. Used to walk the component instances on a dispatch path
|
|
311
|
+
// (filter via Components.getCompFor).
|
|
345
312
|
resolveChain(root) {
|
|
346
313
|
const out = [root];
|
|
347
314
|
let curVal = root;
|
|
@@ -355,7 +322,7 @@ var Path = class _Path {
|
|
|
355
322
|
// A flat `[{ field, key? }]` list of the addressing steps, skipping frame-only
|
|
356
323
|
// steps (binds). Generic path introspection so tooling (e.g. the storybook
|
|
357
324
|
// activity log) can identify which subtree a transaction touched without
|
|
358
|
-
// depending on Step internals.
|
|
325
|
+
// depending on Step internals.
|
|
359
326
|
toKeys() {
|
|
360
327
|
const out = [];
|
|
361
328
|
for (const step of this.steps) {
|
|
@@ -376,62 +343,147 @@ var Path = class _Path {
|
|
|
376
343
|
});
|
|
377
344
|
}
|
|
378
345
|
buildStack(stack) {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
346
|
+
return walkItems(stack, this.steps, stack.renderPath ?? new DispatchPath(), this)?.[0] ?? null;
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
function walkItems(stack, items, renderPath, path2) {
|
|
350
|
+
let prev = stack.it;
|
|
351
|
+
for (const step of items) {
|
|
352
|
+
const next = step.lookup(prev, NONE);
|
|
353
|
+
if (next === NONE) {
|
|
354
|
+
console.warn("bad PathItem", { root: stack.it, step, path: path2 });
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
renderPath = renderPath.pushItem(step);
|
|
358
|
+
stack = step.enterFrame(stack, next, renderPath);
|
|
359
|
+
prev = next;
|
|
360
|
+
}
|
|
361
|
+
return [stack, renderPath];
|
|
362
|
+
}
|
|
363
|
+
var EMPTY_PATH = new Path([]);
|
|
364
|
+
var DispatchPath = class _DispatchPath {
|
|
365
|
+
constructor(frames = [{ base: EMPTY_PATH, items: [] }]) {
|
|
366
|
+
this.frames = frames;
|
|
367
|
+
}
|
|
368
|
+
// Plain addressing steps in one frame based at the root: what a caller means
|
|
369
|
+
// by "this position" when it has no continuation of its own.
|
|
370
|
+
static ofSteps(steps) {
|
|
371
|
+
return new _DispatchPath([{ base: EMPTY_PATH, items: steps.slice() }]);
|
|
372
|
+
}
|
|
373
|
+
get top() {
|
|
374
|
+
return this.frames[this.frames.length - 1];
|
|
375
|
+
}
|
|
376
|
+
_withTopItems(items) {
|
|
377
|
+
const frames = this.frames.slice();
|
|
378
|
+
frames[frames.length - 1] = { base: this.top.base, items };
|
|
379
|
+
return new _DispatchPath(frames);
|
|
380
|
+
}
|
|
381
|
+
concat(steps) {
|
|
382
|
+
if (this.frames.length === 0) return _DispatchPath.ofSteps(steps);
|
|
383
|
+
return this._withTopItems(this.top.items.concat(steps));
|
|
384
|
+
}
|
|
385
|
+
pushItem(step) {
|
|
386
|
+
return this.concat([step]);
|
|
387
|
+
}
|
|
388
|
+
pushFrame(base) {
|
|
389
|
+
return new _DispatchPath(this.frames.concat({ base, items: [] }));
|
|
390
|
+
}
|
|
391
|
+
// Whether bubbling has anywhere left to go: another step in this frame, or a
|
|
392
|
+
// visual caller underneath it.
|
|
393
|
+
canPop() {
|
|
394
|
+
const n = this.frames.length;
|
|
395
|
+
return n > 1 || n === 1 && this.frames[0].items.length > 0;
|
|
396
|
+
}
|
|
397
|
+
isRoot() {
|
|
398
|
+
return this.toTransactionPath().steps.length === 0;
|
|
399
|
+
}
|
|
400
|
+
// One component closer to the root. At the top of a frame that is popping back
|
|
401
|
+
// to the visual caller, not to the producer's own parent — the caller is where
|
|
402
|
+
// the `*name` was written, and where an unhandled message should keep going.
|
|
403
|
+
popStep() {
|
|
404
|
+
const n = this.frames.length;
|
|
405
|
+
if (n === 0) return this;
|
|
406
|
+
const top = this.frames[n - 1];
|
|
407
|
+
if (top.items.length > 0) return this._withTopItems(top.items.slice(0, -1));
|
|
408
|
+
if (n > 1) return new _DispatchPath(this.frames.slice(0, -1));
|
|
409
|
+
return this;
|
|
410
|
+
}
|
|
411
|
+
// Drop frame-only steps inside every frame independently; a frame's base is
|
|
412
|
+
// already addressing-only.
|
|
413
|
+
compact() {
|
|
414
|
+
return new _DispatchPath(
|
|
415
|
+
this.frames.map(({ base, items }) => ({ base, items: new Path(items).compact().steps }))
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
// A stable string for the ADDRESS this path denotes, for the render cache. The
|
|
419
|
+
// same immutable value can sit at two places in the tree, and a subtree rendered
|
|
420
|
+
// at one of them bakes that address in — the provides it publishes are located
|
|
421
|
+
// there. Frame-only steps address nothing, so they are compacted out: two sites
|
|
422
|
+
// that differ only in binds do render the same subtree.
|
|
423
|
+
get addressKey() {
|
|
424
|
+
this._addressKey ??= renderPathText(this.toTransactionPath().compact());
|
|
425
|
+
return this._addressKey;
|
|
426
|
+
}
|
|
427
|
+
// The active transaction address: the top frame's absolute base followed by
|
|
428
|
+
// its ordinary descendant steps. This is where a mutation lands.
|
|
429
|
+
toTransactionPath() {
|
|
430
|
+
const top = this.top;
|
|
431
|
+
return top === void 0 ? EMPTY_PATH : top.base.concat(top.items);
|
|
432
|
+
}
|
|
433
|
+
// Rebuild the render stack this path was dispatched from. A frame with a base
|
|
434
|
+
// re-enters at that absolute value first — replaying the resume a `*name`
|
|
435
|
+
// render performed — and then walks its ordinary items.
|
|
436
|
+
buildStack(stack) {
|
|
437
|
+
let renderPath = new _DispatchPath();
|
|
438
|
+
for (let i = 0; i < this.frames.length; i++) {
|
|
439
|
+
const { base, items } = this.frames[i];
|
|
440
|
+
if (i > 0 || base.steps.length > 0) {
|
|
441
|
+
const baseValue = base.lookup(stack.root, NONE);
|
|
442
|
+
if (baseValue === NONE) {
|
|
443
|
+
console.warn("bad frame base", { base, path: this });
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
446
|
+
renderPath = renderPath.pushFrame(base);
|
|
447
|
+
stack = stack.enter(baseValue, {}, true, renderPath);
|
|
385
448
|
}
|
|
386
|
-
|
|
387
|
-
|
|
449
|
+
const walked = walkItems(stack, items, renderPath, this);
|
|
450
|
+
if (walked === null) return null;
|
|
451
|
+
[stack, renderPath] = walked;
|
|
388
452
|
}
|
|
389
453
|
return stack;
|
|
390
454
|
}
|
|
391
455
|
static fromNodeAndEventName(node, eventName, rootNode, maxDepth, comps, stopOnNoEvent = true) {
|
|
392
|
-
const
|
|
393
|
-
const pendingDyns = [];
|
|
456
|
+
const parts = [];
|
|
394
457
|
const bubbles = BUBBLING_EVENTS.has(eventName);
|
|
395
458
|
let depth = 0;
|
|
396
459
|
let eventIds = [];
|
|
397
460
|
let handlers = null;
|
|
398
|
-
let
|
|
461
|
+
let nodeRefs = [];
|
|
399
462
|
let isLeafComponent = true;
|
|
400
463
|
const crossComponent = (cidNum, vid) => {
|
|
401
464
|
const comp = comps.getComponentForId(cidNum);
|
|
402
|
-
let
|
|
465
|
+
let pushPart = true;
|
|
403
466
|
if (handlers === null && (isLeafComponent || bubbles)) {
|
|
404
467
|
handlers = findHandlers(comp, eventIds, vid, eventName);
|
|
405
468
|
if (handlers === null) {
|
|
406
469
|
if (isLeafComponent && stopOnNoEvent && !bubbles) return false;
|
|
407
470
|
} else if (!isLeafComponent) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
pushStep = false;
|
|
471
|
+
parts.length = 0;
|
|
472
|
+
pushPart = false;
|
|
411
473
|
}
|
|
412
474
|
}
|
|
413
475
|
isLeafComponent = false;
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
if (step) {
|
|
418
|
-
step._originCid = cidNum;
|
|
419
|
-
pathSteps.push(step);
|
|
420
|
-
if (step instanceof DynStep) {
|
|
421
|
-
step.interiorCids.add(cidNum);
|
|
422
|
-
pendingDyns.push(step);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
476
|
+
if (pushPart) {
|
|
477
|
+
const part = resolvePathPart(comp, nodeRefs, vid);
|
|
478
|
+
if (part) parts.push(part);
|
|
425
479
|
}
|
|
426
|
-
for (let i = pendingDyns.length - 1; i >= 0; i--)
|
|
427
|
-
if (pendingDyns[i].producerCompId === cidNum) pendingDyns.splice(i, 1);
|
|
428
480
|
eventIds = [];
|
|
429
|
-
|
|
481
|
+
nodeRefs = [];
|
|
430
482
|
return true;
|
|
431
483
|
};
|
|
432
484
|
while (node && node !== rootNode && depth < maxDepth) {
|
|
433
485
|
if (node?.dataset) {
|
|
434
|
-
const { eid, cid, vid } = node.dataset;
|
|
486
|
+
const { eid, cid, vid, rp } = node.dataset;
|
|
435
487
|
if (eid !== void 0) eventIds.push(eid);
|
|
436
488
|
const metas = metaChain(node.previousSibling);
|
|
437
489
|
let sawComp = false;
|
|
@@ -439,21 +491,47 @@ var Path = class _Path {
|
|
|
439
491
|
if (m.$ === "Comp") {
|
|
440
492
|
sawComp = true;
|
|
441
493
|
if (!crossComponent(m.cid, m.vid)) return NO_EVENT_INFO;
|
|
442
|
-
|
|
494
|
+
nodeRefs.push({ nid: m.nid, base: pathFromJson(m.base) });
|
|
443
495
|
} else {
|
|
444
|
-
|
|
496
|
+
nodeRefs.push({ nid: m.nid, si: m.si, sk: m.sk });
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if (!sawComp && cid !== void 0) {
|
|
500
|
+
if (!crossComponent(+cid, vid)) return NO_EVENT_INFO;
|
|
501
|
+
if (rp !== void 0) {
|
|
502
|
+
const base = parseRenderPath(rp);
|
|
503
|
+
if (base !== null) nodeRefs.push({ base });
|
|
445
504
|
}
|
|
446
505
|
}
|
|
447
|
-
if (!sawComp && cid !== void 0 && !crossComponent(+cid, vid)) return NO_EVENT_INFO;
|
|
448
506
|
}
|
|
449
507
|
depth += 1;
|
|
450
508
|
node = node.parentNode;
|
|
451
509
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
510
|
+
parts.reverse();
|
|
511
|
+
let path2 = new _DispatchPath();
|
|
512
|
+
for (const part of parts)
|
|
513
|
+
path2 = part.base !== void 0 ? path2.pushFrame(part.base) : path2.pushItem(part.step);
|
|
514
|
+
return [path2, handlers];
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
function keyedPath(path2, key) {
|
|
518
|
+
const steps = path2.steps;
|
|
519
|
+
const last = steps[steps.length - 1];
|
|
520
|
+
if (last instanceof SeqStep || last instanceof FieldStep)
|
|
521
|
+
return new Path(steps.slice(0, -1).concat(new SeqStep(last.field, key)));
|
|
522
|
+
return null;
|
|
523
|
+
}
|
|
524
|
+
function renderPathText(path2) {
|
|
525
|
+
return JSON.stringify(pathToJson(path2));
|
|
526
|
+
}
|
|
527
|
+
function parseRenderPath(text) {
|
|
528
|
+
try {
|
|
529
|
+
return pathFromJson(JSON.parse(text));
|
|
530
|
+
} catch (err) {
|
|
531
|
+
console.warn("bad render path", err, text);
|
|
532
|
+
return null;
|
|
455
533
|
}
|
|
456
|
-
}
|
|
534
|
+
}
|
|
457
535
|
function metaChain(n) {
|
|
458
536
|
const out = [];
|
|
459
537
|
while (n?.nodeType === 8 && n.textContent[0] === "§") {
|
|
@@ -506,20 +584,27 @@ var StepCtx = class _StepCtx {
|
|
|
506
584
|
return pi;
|
|
507
585
|
}
|
|
508
586
|
};
|
|
509
|
-
function
|
|
510
|
-
for (let i = 0; i <
|
|
511
|
-
const
|
|
512
|
-
|
|
513
|
-
if (
|
|
587
|
+
function resolvePathPart(comp, nodeRefs, vid) {
|
|
588
|
+
for (let i = 0; i < nodeRefs.length; i++) {
|
|
589
|
+
const ref = nodeRefs[i];
|
|
590
|
+
if (ref.base != null) return { base: ref.base };
|
|
591
|
+
if (ref.nid === void 0 || ref.nid === null) continue;
|
|
592
|
+
const ctx = new StepCtx(comp, nodeRefs, i, vid);
|
|
593
|
+
const step = ctx.resolveNode()?.toPathStep(ctx) ?? null;
|
|
594
|
+
if (step !== null) return { step };
|
|
514
595
|
}
|
|
515
596
|
return null;
|
|
516
597
|
}
|
|
517
598
|
var NO_EVENT_INFO = [null, null];
|
|
518
599
|
var BUBBLING_EVENTS = /* @__PURE__ */ new Set(["drop"]);
|
|
600
|
+
var path = () => new PathBuilder();
|
|
519
601
|
var PathBuilder = class {
|
|
520
602
|
constructor() {
|
|
521
603
|
this.pathChanges = [];
|
|
522
604
|
}
|
|
605
|
+
toPath() {
|
|
606
|
+
return new Path(this.pathChanges);
|
|
607
|
+
}
|
|
523
608
|
add(pathChange) {
|
|
524
609
|
this.pathChanges.push(pathChange);
|
|
525
610
|
return this;
|
|
@@ -1676,13 +1761,16 @@ function h(tagName, properties, children, namespace) {
|
|
|
1676
1761
|
}
|
|
1677
1762
|
|
|
1678
1763
|
// src/anode.js
|
|
1679
|
-
function
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1764
|
+
function renderTarget(val, stack) {
|
|
1765
|
+
if (val instanceof DynVal) {
|
|
1766
|
+
const loc = stack.lookupDynamicLocated(val.name);
|
|
1767
|
+
if (loc?.path == null) return [loc?.value ?? null, stack.renderPath, null];
|
|
1768
|
+
return [loc.value, stack.renderPath.pushFrame(loc.path), loc.path];
|
|
1769
|
+
}
|
|
1770
|
+
const step = val.toPathItem?.() ?? null;
|
|
1771
|
+
if (step === null) return [val.eval(stack), stack.renderPath, null];
|
|
1772
|
+
const path2 = stack.renderPath.pushItem(step);
|
|
1773
|
+
return [val.eval(stack), path2, stack.pendingFrame ? path2.toTransactionPath() : null];
|
|
1686
1774
|
}
|
|
1687
1775
|
var BaseNode = class {
|
|
1688
1776
|
render(_stack, _rx) {
|
|
@@ -2004,33 +2092,31 @@ var RenderViewId = class extends ANode {
|
|
|
2004
2092
|
setDataAttr(_key, _val) {
|
|
2005
2093
|
}
|
|
2006
2094
|
};
|
|
2007
|
-
function dynRenderStep(comp, name, key) {
|
|
2008
|
-
const p = resolveDynProducer(comp, name);
|
|
2009
|
-
if (!p) return null;
|
|
2010
|
-
return key === void 0 ? new DynStep(p.producerCompId, p.producerSteps) : new DynEachStep(p.producerCompId, p.producerSteps, key);
|
|
2011
|
-
}
|
|
2012
2095
|
var RenderNode = class extends RenderViewId {
|
|
2013
2096
|
render(stack, rx) {
|
|
2014
|
-
const
|
|
2015
|
-
|
|
2097
|
+
const [value, renderPath, base] = renderTarget(this.val, stack);
|
|
2098
|
+
const newStack = stack.enter(value, {}, true, renderPath, false);
|
|
2099
|
+
return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
|
|
2016
2100
|
}
|
|
2101
|
+
// A `*name` target contributes no step: the site recorded the absolute base it
|
|
2102
|
+
// resumed at, and event reconstruction turns that into a continuation frame.
|
|
2017
2103
|
toPathStep(ctx) {
|
|
2018
|
-
if (this.val instanceof DynVal) return
|
|
2104
|
+
if (this.val instanceof DynVal) return null;
|
|
2019
2105
|
return super.toPathStep(ctx);
|
|
2020
2106
|
}
|
|
2021
2107
|
};
|
|
2022
2108
|
var RenderItNode = class extends RenderViewId {
|
|
2023
2109
|
render(stack, rx) {
|
|
2024
|
-
const
|
|
2025
|
-
|
|
2110
|
+
const base = stack.pendingFrame ? stack.renderPath.toTransactionPath() : null;
|
|
2111
|
+
const newStack = stack.enter(stack.it, {}, true, stack.renderPath, false);
|
|
2112
|
+
return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
|
|
2026
2113
|
}
|
|
2027
2114
|
toPathStep(ctx) {
|
|
2028
2115
|
const next = ctx.next();
|
|
2029
2116
|
if (next === null) return null;
|
|
2030
2117
|
const nextNode = next.resolveNode();
|
|
2031
2118
|
if (nextNode instanceof EachNode && next.hasKey) {
|
|
2032
|
-
if (nextNode.val instanceof DynVal)
|
|
2033
|
-
return dynRenderStep(ctx.comp, nextNode.val.name, next.key);
|
|
2119
|
+
if (nextNode.val instanceof DynVal) return null;
|
|
2034
2120
|
return new EachRenderItStep(nextNode.val.name, next.key);
|
|
2035
2121
|
}
|
|
2036
2122
|
return null;
|
|
@@ -2132,11 +2218,19 @@ var EachNode = class extends WrapperNode {
|
|
|
2132
2218
|
this.iterInfo = new IterInfo(val, null, null, null);
|
|
2133
2219
|
}
|
|
2134
2220
|
render(stack, rx) {
|
|
2135
|
-
return rx.renderEachWhen(stack, this
|
|
2221
|
+
return rx.renderEachWhen(stack, this);
|
|
2136
2222
|
}
|
|
2137
2223
|
toPathStep(ctx) {
|
|
2138
2224
|
return ctx.hasKey ? new EachBindStep(this.iterInfo, ctx.key) : null;
|
|
2139
2225
|
}
|
|
2226
|
+
// Where one item lives, for the render path. `@each` re-binds `it` to the item
|
|
2227
|
+
// whether or not the body is a component, so the position moves either way and
|
|
2228
|
+
// the step has to address it — `.rows` iterated at `key` IS `rows[key]`.
|
|
2229
|
+
// Null for a dynamic sequence: `*rows` carries its own absolute path and enters
|
|
2230
|
+
// a continuation frame instead (see Renderer.renderEachWhen).
|
|
2231
|
+
itemStep(key) {
|
|
2232
|
+
return this.val instanceof FieldVal ? new SeqStep(this.val.name, key) : null;
|
|
2233
|
+
}
|
|
2140
2234
|
static register = true;
|
|
2141
2235
|
};
|
|
2142
2236
|
var IterInfo = class {
|
|
@@ -2397,6 +2491,215 @@ function compileModifiers(eventName, names) {
|
|
|
2397
2491
|
};
|
|
2398
2492
|
}
|
|
2399
2493
|
|
|
2494
|
+
// src/stack.js
|
|
2495
|
+
var STOP = /* @__PURE__ */ Symbol("STOP");
|
|
2496
|
+
var NEXT = /* @__PURE__ */ Symbol("NEXT");
|
|
2497
|
+
var DEFAULT_ROUTE = ["dyn", "lex"];
|
|
2498
|
+
function routeLookup(route, lex, dyn) {
|
|
2499
|
+
for (let i = 0; i < route.length; i++) {
|
|
2500
|
+
const leg = route[i];
|
|
2501
|
+
if (leg === "dyn") {
|
|
2502
|
+
const v = dyn();
|
|
2503
|
+
if (v != null) return v;
|
|
2504
|
+
} else if (leg === "lex") {
|
|
2505
|
+
const v = lex();
|
|
2506
|
+
if (v != null) return v;
|
|
2507
|
+
} else {
|
|
2508
|
+
console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
return null;
|
|
2512
|
+
}
|
|
2513
|
+
var isTypeName = (s) => {
|
|
2514
|
+
const c = s.charCodeAt(0);
|
|
2515
|
+
return c >= 65 && c <= 90;
|
|
2516
|
+
};
|
|
2517
|
+
function lookup(chain, name, dv = null) {
|
|
2518
|
+
let n = chain;
|
|
2519
|
+
while (n !== null) {
|
|
2520
|
+
const r = n[0].lookup(name);
|
|
2521
|
+
if (r === STOP) return dv;
|
|
2522
|
+
if (r !== NEXT) return r;
|
|
2523
|
+
n = n[1];
|
|
2524
|
+
}
|
|
2525
|
+
return dv;
|
|
2526
|
+
}
|
|
2527
|
+
var BindFrame = class {
|
|
2528
|
+
constructor(it, binds, isFrame) {
|
|
2529
|
+
this.it = it;
|
|
2530
|
+
this.binds = binds;
|
|
2531
|
+
this.isFrame = isFrame;
|
|
2532
|
+
}
|
|
2533
|
+
lookup(name) {
|
|
2534
|
+
const v = this.binds[name];
|
|
2535
|
+
return v === void 0 ? this.isFrame ? STOP : NEXT : v;
|
|
2536
|
+
}
|
|
2537
|
+
};
|
|
2538
|
+
var DynFrame = class {
|
|
2539
|
+
constructor(binds, types) {
|
|
2540
|
+
this.binds = binds;
|
|
2541
|
+
this.types = types;
|
|
2542
|
+
}
|
|
2543
|
+
lookup(name) {
|
|
2544
|
+
const v = (isTypeName(name) ? this.types : this.binds)[name];
|
|
2545
|
+
return v === void 0 ? NEXT : v;
|
|
2546
|
+
}
|
|
2547
|
+
};
|
|
2548
|
+
function computeViewsId(views) {
|
|
2549
|
+
let s = "";
|
|
2550
|
+
let n = views;
|
|
2551
|
+
while (n !== null) {
|
|
2552
|
+
s += n[0];
|
|
2553
|
+
n = n[1];
|
|
2554
|
+
}
|
|
2555
|
+
return s === "main" ? "" : s;
|
|
2556
|
+
}
|
|
2557
|
+
var Stack = class _Stack {
|
|
2558
|
+
constructor(fields) {
|
|
2559
|
+
Object.assign(this, fields);
|
|
2560
|
+
}
|
|
2561
|
+
_with(patch) {
|
|
2562
|
+
return new _Stack({ ...this, ...patch });
|
|
2563
|
+
}
|
|
2564
|
+
// Evaluate every provide the entered component publishes and push them as one
|
|
2565
|
+
// dynBinds frame, keyed by NAME. A value is published together with the absolute
|
|
2566
|
+
// path it lives at: the same declaration is read as `*name` AND resumed at by
|
|
2567
|
+
// `<x render="*name">`, so a consumer needs both halves. Types go in the same
|
|
2568
|
+
// frame's other map. No-op with no provides.
|
|
2569
|
+
_pushProvides() {
|
|
2570
|
+
const comp = this.comps.getCompFor(this.it);
|
|
2571
|
+
if (comp == null) return this;
|
|
2572
|
+
const { provide, provideType } = comp;
|
|
2573
|
+
const binds = {};
|
|
2574
|
+
const types = {};
|
|
2575
|
+
let has = false;
|
|
2576
|
+
const base = this._publishBase();
|
|
2577
|
+
for (const k in provide) {
|
|
2578
|
+
const step = provide[k].val.toPathItem?.() ?? null;
|
|
2579
|
+
if (step === null) continue;
|
|
2580
|
+
const value = provide[k].val.eval(this);
|
|
2581
|
+
binds[k] = { value, path: base === null ? null : base.concat([step]) };
|
|
2582
|
+
has = true;
|
|
2583
|
+
}
|
|
2584
|
+
for (const k in provideType) {
|
|
2585
|
+
types[k] = provideType[k];
|
|
2586
|
+
has = true;
|
|
2587
|
+
}
|
|
2588
|
+
if (!has) return this;
|
|
2589
|
+
return this._with({ dynBinds: [new DynFrame(binds, types), this.dynBinds] });
|
|
2590
|
+
}
|
|
2591
|
+
// The absolute address of the component being entered, or null when this
|
|
2592
|
+
// position cannot be written down as one. Frame-only steps carry bindings and
|
|
2593
|
+
// address nothing, so they are compacted away first; what is left is checked
|
|
2594
|
+
// against the value actually being rendered, because a scope CAN move the
|
|
2595
|
+
// render position without contributing an addressing step (a plain `@each`
|
|
2596
|
+
// body re-binds `it` to the item while its rebuild step is an identity).
|
|
2597
|
+
//
|
|
2598
|
+
// A null base still publishes the VALUE — `*name` reads it fine — but there is
|
|
2599
|
+
// nowhere to resume, so `<x render="*name">` renders nothing rather than
|
|
2600
|
+
// editing whatever happens to live at the address we guessed.
|
|
2601
|
+
_publishBase() {
|
|
2602
|
+
const base = this.renderPath.toTransactionPath().compact();
|
|
2603
|
+
return base.lookup(this.root, NOT_FOUND) === this.it ? base : null;
|
|
2604
|
+
}
|
|
2605
|
+
static root(comps, it, ctx = null) {
|
|
2606
|
+
return new _Stack({
|
|
2607
|
+
comps,
|
|
2608
|
+
root: it,
|
|
2609
|
+
it,
|
|
2610
|
+
binds: [new BindFrame(it, {}, true), null],
|
|
2611
|
+
dynBinds: [new DynFrame({}, {}), null],
|
|
2612
|
+
views: ["main", null],
|
|
2613
|
+
viewsId: "",
|
|
2614
|
+
renderPath: new DispatchPath(),
|
|
2615
|
+
pendingFrame: false,
|
|
2616
|
+
ctx
|
|
2617
|
+
})._pushProvides();
|
|
2618
|
+
}
|
|
2619
|
+
// `renderPath` defaults to this stack's own: an ordinary scope does not move.
|
|
2620
|
+
// `pendingFrame` clears on a component frame (which emits the base) and is
|
|
2621
|
+
// inherited by transparent scopes, which have to carry it to the next boundary.
|
|
2622
|
+
enter(it, bindings = {}, isFrame = true, renderPath = this.renderPath, pendingFrame = null) {
|
|
2623
|
+
const stack = this._with({
|
|
2624
|
+
it,
|
|
2625
|
+
binds: [new BindFrame(it, bindings, isFrame), this.binds],
|
|
2626
|
+
renderPath,
|
|
2627
|
+
pendingFrame: pendingFrame ?? (isFrame ? false : this.pendingFrame)
|
|
2628
|
+
});
|
|
2629
|
+
return isFrame ? stack._pushProvides() : stack;
|
|
2630
|
+
}
|
|
2631
|
+
pushViewName(name) {
|
|
2632
|
+
const views = [name, this.views];
|
|
2633
|
+
return this._with({ views, viewsId: computeViewsId(views) });
|
|
2634
|
+
}
|
|
2635
|
+
// Published types are stable per scope and would only churn the render cache, so
|
|
2636
|
+
// the cache key covers values alone.
|
|
2637
|
+
_pushDynBindValuesToArray(arr, comp) {
|
|
2638
|
+
for (const k in comp.provide) arr.push(this.lookupDynamic(k));
|
|
2639
|
+
for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
|
|
2640
|
+
}
|
|
2641
|
+
// `*name`: the nearest binding above (including this component's own provides,
|
|
2642
|
+
// pushed on entering it), else a path registered in the component's lexical
|
|
2643
|
+
// scope, else this component's declared default, else null.
|
|
2644
|
+
//
|
|
2645
|
+
// One chain walk and no producer resolution: a lookup names what it WANTS, so the
|
|
2646
|
+
// frame it wants is keyed by that name. The default belongs to the CONSUMER's
|
|
2647
|
+
// declaration and is evaluated against the consumer's stack, which is why it is
|
|
2648
|
+
// consulted only after the whole chain has missed.
|
|
2649
|
+
lookupDynamicLocated(name) {
|
|
2650
|
+
if (isTypeName(name)) return null;
|
|
2651
|
+
const v = lookup(this.dynBinds, name);
|
|
2652
|
+
if (v != null) return v;
|
|
2653
|
+
const comp = this.comps.getCompFor(this.it);
|
|
2654
|
+
if (comp == null) return null;
|
|
2655
|
+
const path2 = comp.scope?.lookupPath?.(name) ?? null;
|
|
2656
|
+
if (path2 !== null) {
|
|
2657
|
+
const value2 = path2.lookup(this.root, NOT_FOUND);
|
|
2658
|
+
if (value2 !== NOT_FOUND) return { value: value2, path: path2 };
|
|
2659
|
+
}
|
|
2660
|
+
const dval = comp.lookup[name]?.val ?? null;
|
|
2661
|
+
if (dval === null) return null;
|
|
2662
|
+
const step = dval.toPathItem?.() ?? null;
|
|
2663
|
+
const value = dval.eval(this);
|
|
2664
|
+
return step === null ? { value, path: null } : { value, path: this.renderPath.toTransactionPath().concat([step]) };
|
|
2665
|
+
}
|
|
2666
|
+
lookupDynamic(name) {
|
|
2667
|
+
if (isTypeName(name)) return lookup(this.dynBinds, name);
|
|
2668
|
+
return this.lookupDynamicLocated(name)?.value ?? null;
|
|
2669
|
+
}
|
|
2670
|
+
lookupBind(name) {
|
|
2671
|
+
return lookup(this.binds, name);
|
|
2672
|
+
}
|
|
2673
|
+
lookupFieldRaw(name) {
|
|
2674
|
+
return this.it[name] ?? null;
|
|
2675
|
+
}
|
|
2676
|
+
lookupMethod(name) {
|
|
2677
|
+
const fn = this.it[name];
|
|
2678
|
+
return fn instanceof Function ? fn.call(this.it) : null;
|
|
2679
|
+
}
|
|
2680
|
+
// The dispatched DOM event / drag info, read only by EventMemberVal's
|
|
2681
|
+
// `e.<member>` handler args. Null outside a live event transaction.
|
|
2682
|
+
lookupEvent() {
|
|
2683
|
+
return this.ctx?.event ?? null;
|
|
2684
|
+
}
|
|
2685
|
+
lookupDragInfo() {
|
|
2686
|
+
return this.ctx?.dragInfo ?? null;
|
|
2687
|
+
}
|
|
2688
|
+
getHandlerFor(name, key) {
|
|
2689
|
+
return this.comps.getHandlerFor(this.it, name, key);
|
|
2690
|
+
}
|
|
2691
|
+
lookupBestView(views, defaultViewName) {
|
|
2692
|
+
let n = this.views;
|
|
2693
|
+
while (n !== null) {
|
|
2694
|
+
const view = views[n[0]];
|
|
2695
|
+
if (view !== void 0) return view;
|
|
2696
|
+
n = n[1];
|
|
2697
|
+
}
|
|
2698
|
+
return views[defaultViewName];
|
|
2699
|
+
}
|
|
2700
|
+
};
|
|
2701
|
+
var NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
|
|
2702
|
+
|
|
2400
2703
|
// src/components.js
|
|
2401
2704
|
var COMPONENT = /* @__PURE__ */ Symbol.for("tutuca.component");
|
|
2402
2705
|
var Components = class {
|
|
@@ -2435,12 +2738,14 @@ var ComponentStack = class _ComponentStack {
|
|
|
2435
2738
|
this.byName = {};
|
|
2436
2739
|
this.intentsByName = {};
|
|
2437
2740
|
this.macros = {};
|
|
2741
|
+
this.paths = {};
|
|
2438
2742
|
}
|
|
2439
2743
|
enter() {
|
|
2440
2744
|
return new _ComponentStack(this.comps, this);
|
|
2441
2745
|
}
|
|
2442
2746
|
registerComponents(comps, opts) {
|
|
2443
|
-
const { aliases = {} } = opts ?? {};
|
|
2747
|
+
const { aliases = {}, paths } = opts ?? {};
|
|
2748
|
+
if (paths) this.registerPaths(paths);
|
|
2444
2749
|
for (let i = 0; i < comps.length; i++) {
|
|
2445
2750
|
const Comp = comps[i];
|
|
2446
2751
|
Comp[COMPONENT].scope = this.enter();
|
|
@@ -2454,6 +2759,27 @@ var ComponentStack = class _ComponentStack {
|
|
|
2454
2759
|
else console.warn("alias", alias, "to inexistent component", aliases[alias]);
|
|
2455
2760
|
}
|
|
2456
2761
|
}
|
|
2762
|
+
// Register lowercase names as absolute paths from the app state root. A
|
|
2763
|
+
// descendant that declares one in its `lookup` reads and renders `*name` without
|
|
2764
|
+
// anything above it publishing one — which is what makes a session, a theme or a
|
|
2765
|
+
// host-owned value available in its natural registration scope, instead of forcing
|
|
2766
|
+
// an application root whose only job is to `provide` it. Register on a nested
|
|
2767
|
+
// scope to narrow a name; nearest registration wins.
|
|
2768
|
+
//
|
|
2769
|
+
// Uppercase names are ignored: a component TYPE is what `lookupComponent` already
|
|
2770
|
+
// answers, and a type has no path.
|
|
2771
|
+
registerPaths(paths) {
|
|
2772
|
+
for (const name in paths) {
|
|
2773
|
+
if (isTypeName(name)) {
|
|
2774
|
+
console.warn("registerPaths: a type name has no path", name);
|
|
2775
|
+
continue;
|
|
2776
|
+
}
|
|
2777
|
+
this.paths[name] = paths[name].toPath?.() ?? paths[name];
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
lookupPath(name) {
|
|
2781
|
+
return this.paths[name] ?? this.parent?.lookupPath(name) ?? null;
|
|
2782
|
+
}
|
|
2457
2783
|
registerMacros(macros) {
|
|
2458
2784
|
for (const key in macros) {
|
|
2459
2785
|
const lower = key.toLowerCase();
|
|
@@ -2485,17 +2811,16 @@ var ComponentStack = class _ComponentStack {
|
|
|
2485
2811
|
lookupComponent(name) {
|
|
2486
2812
|
return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
|
|
2487
2813
|
}
|
|
2488
|
-
//
|
|
2489
|
-
// names
|
|
2490
|
-
//
|
|
2491
|
-
//
|
|
2492
|
-
//
|
|
2493
|
-
|
|
2814
|
+
// Whether anything in this scope chain provides `name`. Existence only: a lookup
|
|
2815
|
+
// names what it WANTS and takes whoever is nearest above it at render time, so
|
|
2816
|
+
// there is no producer to identify — several components may publish one name and
|
|
2817
|
+
// the live render ancestry decides. Used by the linter to tell a lookup that can
|
|
2818
|
+
// be satisfied from one that never will be.
|
|
2819
|
+
hasProvider(name) {
|
|
2494
2820
|
for (const compName in this.byName) {
|
|
2495
|
-
|
|
2496
|
-
if (Comp.provide?.[name] !== void 0) return Comp;
|
|
2821
|
+
if (this.byName[compName].provide?.[name] !== void 0) return true;
|
|
2497
2822
|
}
|
|
2498
|
-
return this.parent?.
|
|
2823
|
+
return this.parent?.hasProvider(name) ?? false;
|
|
2499
2824
|
}
|
|
2500
2825
|
lookupMacro(name) {
|
|
2501
2826
|
return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
|
|
@@ -2512,10 +2837,6 @@ var LookupInfo = class {
|
|
|
2512
2837
|
}
|
|
2513
2838
|
};
|
|
2514
2839
|
var isString = (v) => typeof v === "string";
|
|
2515
|
-
var isTypeName = (s) => {
|
|
2516
|
-
const c = s.charCodeAt(0);
|
|
2517
|
-
return c >= 65 && c <= 90;
|
|
2518
|
-
};
|
|
2519
2840
|
var _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
|
|
2520
2841
|
var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
|
|
2521
2842
|
var _compId = 0;
|
|
@@ -2588,160 +2909,6 @@ var Component = class {
|
|
|
2588
2909
|
}
|
|
2589
2910
|
};
|
|
2590
2911
|
|
|
2591
|
-
// src/stack.js
|
|
2592
|
-
var STOP = /* @__PURE__ */ Symbol("STOP");
|
|
2593
|
-
var NEXT = /* @__PURE__ */ Symbol("NEXT");
|
|
2594
|
-
var DEFAULT_ROUTE = ["dyn", "lex"];
|
|
2595
|
-
function routeLookup(route, lex, dyn) {
|
|
2596
|
-
for (let i = 0; i < route.length; i++) {
|
|
2597
|
-
const leg = route[i];
|
|
2598
|
-
if (leg === "dyn") {
|
|
2599
|
-
const v = dyn();
|
|
2600
|
-
if (v != null) return v;
|
|
2601
|
-
} else if (leg === "lex") {
|
|
2602
|
-
const v = lex();
|
|
2603
|
-
if (v != null) return v;
|
|
2604
|
-
} else {
|
|
2605
|
-
console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
|
|
2606
|
-
}
|
|
2607
|
-
}
|
|
2608
|
-
return null;
|
|
2609
|
-
}
|
|
2610
|
-
function lookup(chain, name, dv = null) {
|
|
2611
|
-
let n = chain;
|
|
2612
|
-
while (n !== null) {
|
|
2613
|
-
const r = n[0].lookup(name);
|
|
2614
|
-
if (r === STOP) return dv;
|
|
2615
|
-
if (r !== NEXT) return r;
|
|
2616
|
-
n = n[1];
|
|
2617
|
-
}
|
|
2618
|
-
return dv;
|
|
2619
|
-
}
|
|
2620
|
-
var BindFrame = class {
|
|
2621
|
-
constructor(it, binds, isFrame) {
|
|
2622
|
-
this.it = it;
|
|
2623
|
-
this.binds = binds;
|
|
2624
|
-
this.isFrame = isFrame;
|
|
2625
|
-
}
|
|
2626
|
-
lookup(name) {
|
|
2627
|
-
const v = this.binds[name];
|
|
2628
|
-
return v === void 0 ? this.isFrame ? STOP : NEXT : v;
|
|
2629
|
-
}
|
|
2630
|
-
};
|
|
2631
|
-
var ObjectFrame = class {
|
|
2632
|
-
constructor(binds) {
|
|
2633
|
-
this.binds = binds;
|
|
2634
|
-
}
|
|
2635
|
-
lookup(key) {
|
|
2636
|
-
const v = this.binds[key];
|
|
2637
|
-
return v === void 0 ? NEXT : v;
|
|
2638
|
-
}
|
|
2639
|
-
};
|
|
2640
|
-
function computeViewsId(views) {
|
|
2641
|
-
let s = "";
|
|
2642
|
-
let n = views;
|
|
2643
|
-
while (n !== null) {
|
|
2644
|
-
s += n[0];
|
|
2645
|
-
n = n[1];
|
|
2646
|
-
}
|
|
2647
|
-
return s === "main" ? "" : s;
|
|
2648
|
-
}
|
|
2649
|
-
var Stack = class _Stack {
|
|
2650
|
-
constructor(comps, it, binds, dynBinds, views, viewsId, ctx = null) {
|
|
2651
|
-
this.comps = comps;
|
|
2652
|
-
this.it = it;
|
|
2653
|
-
this.binds = binds;
|
|
2654
|
-
this.dynBinds = dynBinds;
|
|
2655
|
-
this.views = views;
|
|
2656
|
-
this.viewsId = viewsId;
|
|
2657
|
-
this.ctx = ctx;
|
|
2658
|
-
}
|
|
2659
|
-
// Evaluate every provide the entered component publishes and push them as one
|
|
2660
|
-
// dynBinds frame, keyed by NAME. Published types go in the same frame: a type name
|
|
2661
|
-
// starts A-Z and a value name does not, so the two namespaces cannot collide and
|
|
2662
|
-
// nearest-ancestor-wins falls out of frame order for both. No-op with no provides.
|
|
2663
|
-
_pushProvides() {
|
|
2664
|
-
const comp = this.comps.getCompFor(this.it);
|
|
2665
|
-
if (comp == null) return this;
|
|
2666
|
-
const { provide, provideType } = comp;
|
|
2667
|
-
const dynObj = {};
|
|
2668
|
-
let has = false;
|
|
2669
|
-
for (const k in provide) {
|
|
2670
|
-
dynObj[k] = provide[k].val.eval(this);
|
|
2671
|
-
has = true;
|
|
2672
|
-
}
|
|
2673
|
-
for (const k in provideType) {
|
|
2674
|
-
dynObj[k] = provideType[k];
|
|
2675
|
-
has = true;
|
|
2676
|
-
}
|
|
2677
|
-
if (!has) return this;
|
|
2678
|
-
const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
|
|
2679
|
-
const { comps, it, binds, views, viewsId, ctx } = this;
|
|
2680
|
-
return new _Stack(comps, it, binds, newDynBinds, views, viewsId, ctx);
|
|
2681
|
-
}
|
|
2682
|
-
static root(comps, it, ctx) {
|
|
2683
|
-
const binds = [new BindFrame(it, {}, true), null];
|
|
2684
|
-
const dynBinds = [new ObjectFrame({}), null];
|
|
2685
|
-
const views = ["main", null];
|
|
2686
|
-
return new _Stack(comps, it, binds, dynBinds, views, "", ctx)._pushProvides();
|
|
2687
|
-
}
|
|
2688
|
-
enter(it, bindings = {}, isFrame = true) {
|
|
2689
|
-
const { comps, binds, dynBinds, views, viewsId, ctx } = this;
|
|
2690
|
-
const newBinds = [new BindFrame(it, bindings, isFrame), binds];
|
|
2691
|
-
const stack = new _Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx);
|
|
2692
|
-
return isFrame ? stack._pushProvides() : stack;
|
|
2693
|
-
}
|
|
2694
|
-
pushViewName(name) {
|
|
2695
|
-
const { comps, it, binds, dynBinds, views, ctx } = this;
|
|
2696
|
-
const newViews = [name, views];
|
|
2697
|
-
return new _Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
|
|
2698
|
-
}
|
|
2699
|
-
// Published types are stable per scope and would only churn the render cache, so
|
|
2700
|
-
// the cache key covers values alone.
|
|
2701
|
-
_pushDynBindValuesToArray(arr, comp) {
|
|
2702
|
-
for (const k in comp.provide) arr.push(this.lookupDynamic(k));
|
|
2703
|
-
for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
|
|
2704
|
-
}
|
|
2705
|
-
// `*name`: the nearest binding above (including this component's own provides,
|
|
2706
|
-
// pushed on entering it), else this component's declared default, else null.
|
|
2707
|
-
lookupDynamic(name) {
|
|
2708
|
-
const v = lookup(this.dynBinds, name);
|
|
2709
|
-
if (v != null) return v;
|
|
2710
|
-
const comp = this.comps.getCompFor(this.it);
|
|
2711
|
-
return comp?.lookup[name]?.val?.eval(this) ?? null;
|
|
2712
|
-
}
|
|
2713
|
-
lookupBind(name) {
|
|
2714
|
-
return lookup(this.binds, name);
|
|
2715
|
-
}
|
|
2716
|
-
lookupFieldRaw(name) {
|
|
2717
|
-
return this.it[name] ?? null;
|
|
2718
|
-
}
|
|
2719
|
-
lookupMethod(name) {
|
|
2720
|
-
const fn = this.it[name];
|
|
2721
|
-
return fn instanceof Function ? fn.call(this.it) : null;
|
|
2722
|
-
}
|
|
2723
|
-
// The dispatched DOM event / drag info, read only by EventMemberVal's
|
|
2724
|
-
// `e.<member>` handler args. Null outside a live event transaction.
|
|
2725
|
-
lookupEvent() {
|
|
2726
|
-
return this.ctx?.event ?? null;
|
|
2727
|
-
}
|
|
2728
|
-
lookupDragInfo() {
|
|
2729
|
-
return this.ctx?.dragInfo ?? null;
|
|
2730
|
-
}
|
|
2731
|
-
getHandlerFor(name, key) {
|
|
2732
|
-
return this.comps.getHandlerFor(this.it, name, key);
|
|
2733
|
-
}
|
|
2734
|
-
lookupBestView(views, defaultViewName) {
|
|
2735
|
-
let n = this.views;
|
|
2736
|
-
while (n !== null) {
|
|
2737
|
-
const view = views[n[0]];
|
|
2738
|
-
if (view !== void 0) return view;
|
|
2739
|
-
n = n[1];
|
|
2740
|
-
}
|
|
2741
|
-
return views[defaultViewName];
|
|
2742
|
-
}
|
|
2743
|
-
};
|
|
2744
|
-
|
|
2745
2912
|
// src/oo.js
|
|
2746
2913
|
var BAD_VALUE = /* @__PURE__ */ Symbol("BadValue");
|
|
2747
2914
|
var nullCoercer = (v) => v;
|
|
@@ -3087,9 +3254,9 @@ var Transactor = class {
|
|
|
3087
3254
|
// `.a[.selId]` render target reconstructed from a DOM event) against the root the
|
|
3088
3255
|
// handler read, so pathKeys carries concrete keys instead of dropping the dynamic
|
|
3089
3256
|
// step. No-op when nobody is observing.
|
|
3090
|
-
_emitRecord(root, { kind, name, args, path, targetPath, handler, handlerName, matched, before, after, parent }) {
|
|
3257
|
+
_emitRecord(root, { kind, name, args, path: path2, targetPath, handler, handlerName, matched, before, after, parent }) {
|
|
3091
3258
|
if (this._observers.length === 0) return;
|
|
3092
|
-
const pinned =
|
|
3259
|
+
const pinned = path2.pinKeys(root);
|
|
3093
3260
|
this._emit({
|
|
3094
3261
|
kind,
|
|
3095
3262
|
name,
|
|
@@ -3140,18 +3307,20 @@ var Transactor = class {
|
|
|
3140
3307
|
// intent's answerPath is: a reply must reach the sender that asked even if a key
|
|
3141
3308
|
// moved while the message was in flight. Null when nobody is waiting — a host
|
|
3142
3309
|
// sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
|
|
3143
|
-
pushSend(
|
|
3144
|
-
const t = new SendEvent(
|
|
3145
|
-
t.
|
|
3310
|
+
pushSend(path2, name, args = [], parent = null, origin = null, txnPath = null) {
|
|
3311
|
+
const t = new SendEvent(path2, this, name, args, parent);
|
|
3312
|
+
t.txnPath = txnPath;
|
|
3313
|
+
t.origin = origin;
|
|
3314
|
+
t.originPinned = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
|
|
3146
3315
|
this.pushTransaction(t);
|
|
3147
3316
|
return this._link(t, parent);
|
|
3148
3317
|
}
|
|
3149
3318
|
// Raise an intent: a job the sender did not address, walked along a route until
|
|
3150
3319
|
// something answers. `opts.route` is a list of legs (see DEFAULT_ROUTE) and
|
|
3151
3320
|
// `opts.livePath` opts out of pinning the answer's destination keys.
|
|
3152
|
-
pushIntent(
|
|
3321
|
+
pushIntent(path2, name, args = [], opts = {}, parent = null) {
|
|
3153
3322
|
const release = parent ? parent.completion.track() : null;
|
|
3154
|
-
const walk = new IntentWalk(this,
|
|
3323
|
+
const walk = new IntentWalk(this, path2, name, args, opts, parent, release);
|
|
3155
3324
|
walk.advance();
|
|
3156
3325
|
return walk;
|
|
3157
3326
|
}
|
|
@@ -3185,16 +3354,17 @@ var Transactor = class {
|
|
|
3185
3354
|
transaction._completion?.releaseSelf();
|
|
3186
3355
|
}
|
|
3187
3356
|
}
|
|
3188
|
-
transactInputNow(
|
|
3189
|
-
this.transact(new InputEvent(
|
|
3357
|
+
transactInputNow(path2, event, eventHandler, dragInfo) {
|
|
3358
|
+
this.transact(new InputEvent(path2, event, eventHandler, this, dragInfo));
|
|
3190
3359
|
}
|
|
3191
3360
|
};
|
|
3192
3361
|
function nullHandler() {
|
|
3193
3362
|
return this;
|
|
3194
3363
|
}
|
|
3195
3364
|
var Transaction = class {
|
|
3196
|
-
constructor(
|
|
3197
|
-
this.path =
|
|
3365
|
+
constructor(path2, transactor, parentTransaction = null) {
|
|
3366
|
+
this.path = path2;
|
|
3367
|
+
this.txnPath = null;
|
|
3198
3368
|
this.transactor = transactor;
|
|
3199
3369
|
this.parentTransaction = parentTransaction;
|
|
3200
3370
|
this._completion = null;
|
|
@@ -3243,9 +3413,11 @@ var Transaction = class {
|
|
|
3243
3413
|
getHandlerAndArgs(_root, _instance, _comps) {
|
|
3244
3414
|
return null;
|
|
3245
3415
|
}
|
|
3246
|
-
// The path used to apply the mutation
|
|
3247
|
-
//
|
|
3416
|
+
// The path used to apply the mutation: the ACTIVE frame of the dispatch path, so
|
|
3417
|
+
// an event inside a `<x render="*name">` subtree updates the value where it
|
|
3418
|
+
// really lives (the dispatch `this.path` keeps the visual callers, for bubbling).
|
|
3248
3419
|
getTransactionPath() {
|
|
3420
|
+
if (this.txnPath !== null) return this.txnPath;
|
|
3249
3421
|
return this.path.toTransactionPath().compact();
|
|
3250
3422
|
}
|
|
3251
3423
|
run(curRoot, comps) {
|
|
@@ -3263,15 +3435,16 @@ var Transaction = class {
|
|
|
3263
3435
|
}
|
|
3264
3436
|
};
|
|
3265
3437
|
var InputEvent = class extends Transaction {
|
|
3266
|
-
constructor(
|
|
3267
|
-
super(
|
|
3438
|
+
constructor(path2, e, handler, transactor, dragInfo) {
|
|
3439
|
+
super(path2, transactor);
|
|
3268
3440
|
this.e = e;
|
|
3269
3441
|
this.handler = handler;
|
|
3270
3442
|
this.dragInfo = dragInfo;
|
|
3271
3443
|
this._dispatchPath = null;
|
|
3272
3444
|
}
|
|
3273
|
-
// Frame steps removed,
|
|
3274
|
-
//
|
|
3445
|
+
// Frame-only steps removed, one step per crossed component kept — inside every
|
|
3446
|
+
// continuation frame independently, so bubbling it visits every component and
|
|
3447
|
+
// then returns to the caller that wrote the `*name`.
|
|
3275
3448
|
get dispatchPath() {
|
|
3276
3449
|
this._dispatchPath ??= this.path.compact();
|
|
3277
3450
|
return this._dispatchPath;
|
|
@@ -3306,11 +3479,11 @@ var InputEvent = class extends Transaction {
|
|
|
3306
3479
|
this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
|
|
3307
3480
|
}
|
|
3308
3481
|
getHandlerAndArgs(root, _instance, comps) {
|
|
3309
|
-
const stack = this.path.
|
|
3482
|
+
const stack = this.path.buildStack(Stack.root(comps, root, this));
|
|
3310
3483
|
const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
|
|
3311
3484
|
this._handlerArgs = [...args];
|
|
3312
|
-
const
|
|
3313
|
-
args.push(new EventContext(
|
|
3485
|
+
const path2 = this.dispatchPath;
|
|
3486
|
+
args.push(new EventContext(path2, this.transactor, this));
|
|
3314
3487
|
return [handler, args];
|
|
3315
3488
|
}
|
|
3316
3489
|
// The dispatched DOM event, read only through `e.<member>` handler args
|
|
@@ -3321,11 +3494,11 @@ var InputEvent = class extends Transaction {
|
|
|
3321
3494
|
}
|
|
3322
3495
|
};
|
|
3323
3496
|
var NameArgsTransaction = class extends Transaction {
|
|
3324
|
-
constructor(
|
|
3325
|
-
super(
|
|
3497
|
+
constructor(path2, transactor, name, args, parentTransaction) {
|
|
3498
|
+
super(path2, transactor, parentTransaction);
|
|
3326
3499
|
this.name = name;
|
|
3327
3500
|
this.args = args;
|
|
3328
|
-
this.targetPath =
|
|
3501
|
+
this.targetPath = path2;
|
|
3329
3502
|
}
|
|
3330
3503
|
handlerProp = null;
|
|
3331
3504
|
// NameArgs verbs map their handler bucket straight to the observed kind:
|
|
@@ -3382,8 +3555,8 @@ var SendEvent = class extends NameArgsTransaction {
|
|
|
3382
3555
|
};
|
|
3383
3556
|
var IntentEvent = class extends NameArgsTransaction {
|
|
3384
3557
|
handlerProp = "intent";
|
|
3385
|
-
constructor(
|
|
3386
|
-
super(
|
|
3558
|
+
constructor(path2, transactor, walk) {
|
|
3559
|
+
super(path2, transactor, walk.name, walk.args, walk.parent);
|
|
3387
3560
|
this.walk = walk;
|
|
3388
3561
|
this.targetPath = walk.origin;
|
|
3389
3562
|
}
|
|
@@ -3410,17 +3583,17 @@ var PASS = /* @__PURE__ */ Symbol.for("tutuca.intent.pass");
|
|
|
3410
3583
|
var REFUSAL_RING_CAP = 200;
|
|
3411
3584
|
var INTENT_DEPTH = 64;
|
|
3412
3585
|
var IntentWalk = class {
|
|
3413
|
-
constructor(transactor,
|
|
3586
|
+
constructor(transactor, path2, name, args, opts, parent, release) {
|
|
3414
3587
|
this.transactor = transactor;
|
|
3415
3588
|
this.name = name;
|
|
3416
3589
|
this.args = args;
|
|
3417
3590
|
this.route = opts?.route ?? DEFAULT_ROUTE;
|
|
3418
3591
|
this.parent = parent;
|
|
3419
3592
|
this.release = release;
|
|
3420
|
-
this.origin =
|
|
3421
|
-
this.answerPath = opts?.livePath ? null :
|
|
3593
|
+
this.origin = path2;
|
|
3594
|
+
this.answerPath = opts?.livePath ? null : path2.toTransactionPath().pinKeys(transactor.state.val);
|
|
3422
3595
|
this.legIndex = 0;
|
|
3423
|
-
this.dynAt =
|
|
3596
|
+
this.dynAt = path2;
|
|
3424
3597
|
this.hops = 0;
|
|
3425
3598
|
this.ended = false;
|
|
3426
3599
|
}
|
|
@@ -3432,7 +3605,7 @@ var IntentWalk = class {
|
|
|
3432
3605
|
while (this.legIndex < this.route.length) {
|
|
3433
3606
|
const leg = this.route[this.legIndex];
|
|
3434
3607
|
if (leg === "dyn") {
|
|
3435
|
-
if (this.dynAt.
|
|
3608
|
+
if (!this.dynAt.canPop()) {
|
|
3436
3609
|
this.legIndex++;
|
|
3437
3610
|
continue;
|
|
3438
3611
|
}
|
|
@@ -3529,8 +3702,8 @@ var IntentWalk = class {
|
|
|
3529
3702
|
if (this.ended) return;
|
|
3530
3703
|
this.ended = true;
|
|
3531
3704
|
if (name === null) return this.release?.();
|
|
3532
|
-
const
|
|
3533
|
-
|
|
3705
|
+
const t = new SendEvent(this.origin, this.transactor, name, args, this.parent);
|
|
3706
|
+
t.txnPath = this.answerPath;
|
|
3534
3707
|
t._isAnswer = true;
|
|
3535
3708
|
this.transactor.pushTransaction(t);
|
|
3536
3709
|
if (this.release) t.completion.whenSubtreeSettled().then(this.release);
|
|
@@ -3596,8 +3769,8 @@ var Completion = class {
|
|
|
3596
3769
|
}
|
|
3597
3770
|
};
|
|
3598
3771
|
var Dispatcher = class {
|
|
3599
|
-
constructor(
|
|
3600
|
-
this.path =
|
|
3772
|
+
constructor(path2, transactor, parentTransaction, root = transactor.state.val) {
|
|
3773
|
+
this.path = path2;
|
|
3601
3774
|
this.transactor = transactor;
|
|
3602
3775
|
this.parent = parentTransaction;
|
|
3603
3776
|
this.root = root;
|
|
@@ -3625,7 +3798,9 @@ var Dispatcher = class {
|
|
|
3625
3798
|
// replayed; provides are pushed on every component frame either way, so a provide
|
|
3626
3799
|
// that reads a loop binding is the one case this cannot reproduce faithfully.
|
|
3627
3800
|
_stack() {
|
|
3628
|
-
this._stackMemo ??= this.path.
|
|
3801
|
+
this._stackMemo ??= this.path.buildStack(
|
|
3802
|
+
Stack.root(this.transactor.comps, this.root, this.parent)
|
|
3803
|
+
);
|
|
3629
3804
|
return this._stackMemo;
|
|
3630
3805
|
}
|
|
3631
3806
|
// Resolve a name the way the renderer would. `opts.route` takes the same legs in
|
|
@@ -3639,14 +3814,19 @@ var Dispatcher = class {
|
|
|
3639
3814
|
);
|
|
3640
3815
|
}
|
|
3641
3816
|
// The `lex` leg without a Stack: the scope of the component whose handler is
|
|
3642
|
-
// running, which is the leaf of this ctx's path.
|
|
3817
|
+
// running, which is the leaf of this ctx's path. A type name resolves to the
|
|
3818
|
+
// component registered under it; a value name to a path registered under it
|
|
3819
|
+
// (see ComponentStack.registerPaths), read against the current root.
|
|
3643
3820
|
_lookupLex(name) {
|
|
3644
3821
|
let Comp = null;
|
|
3645
3822
|
this.walkPath((c) => {
|
|
3646
3823
|
Comp = c;
|
|
3647
3824
|
return false;
|
|
3648
3825
|
});
|
|
3649
|
-
|
|
3826
|
+
const scope = Comp?.scope;
|
|
3827
|
+
if (scope == null) return null;
|
|
3828
|
+
if (isTypeName(name)) return scope.lookupComponent(name) ?? null;
|
|
3829
|
+
return scope.lookupPath(name)?.lookup(this.root) ?? null;
|
|
3650
3830
|
}
|
|
3651
3831
|
// A component lookup is a value lookup constrained to a component. The `lex` leg
|
|
3652
3832
|
// can only ever answer with one; the `dyn` leg reads a binding an ancestor
|
|
@@ -3668,8 +3848,8 @@ var Dispatcher = class {
|
|
|
3668
3848
|
send(name, args) {
|
|
3669
3849
|
return this.sendAtPath(this.path, name, args);
|
|
3670
3850
|
}
|
|
3671
|
-
sendAtPath(
|
|
3672
|
-
return this.transactor.pushSend(
|
|
3851
|
+
sendAtPath(path2, name, args) {
|
|
3852
|
+
return this.transactor.pushSend(path2, name, args, this.parent, this.path);
|
|
3673
3853
|
}
|
|
3674
3854
|
// An intent is ROUTED: it names a job and walks until something answers. The verb
|
|
3675
3855
|
// does not decide which scope answers — `opts.route` does, written here at the call
|
|
@@ -3677,8 +3857,8 @@ var Dispatcher = class {
|
|
|
3677
3857
|
intent(name, args, opts) {
|
|
3678
3858
|
return this.intentAtPath(this.path, name, args, opts);
|
|
3679
3859
|
}
|
|
3680
|
-
intentAtPath(
|
|
3681
|
-
return this.transactor.pushIntent(
|
|
3860
|
+
intentAtPath(path2, name, args, opts) {
|
|
3861
|
+
return this.transactor.pushIntent(path2, name, args, opts, this.parent);
|
|
3682
3862
|
}
|
|
3683
3863
|
};
|
|
3684
3864
|
var EventContext = class extends Dispatcher {
|
|
@@ -3707,7 +3887,14 @@ var EventContext = class extends Dispatcher {
|
|
|
3707
3887
|
this.transactor.refuse("NO_SENDER", { name });
|
|
3708
3888
|
return null;
|
|
3709
3889
|
}
|
|
3710
|
-
return this.
|
|
3890
|
+
return this.transactor.pushSend(
|
|
3891
|
+
origin,
|
|
3892
|
+
name,
|
|
3893
|
+
args,
|
|
3894
|
+
this.parent,
|
|
3895
|
+
this.path,
|
|
3896
|
+
this.parent.originPinned
|
|
3897
|
+
);
|
|
3711
3898
|
}
|
|
3712
3899
|
// End the walk answering nothing — "served, and no answer".
|
|
3713
3900
|
stop() {
|
|
@@ -3739,7 +3926,7 @@ var PathChanges = class extends PathBuilder {
|
|
|
3739
3926
|
}
|
|
3740
3927
|
};
|
|
3741
3928
|
function rootDispatcher(transactor) {
|
|
3742
|
-
return new Dispatcher(new
|
|
3929
|
+
return new Dispatcher(new DispatchPath(), transactor, null);
|
|
3743
3930
|
}
|
|
3744
3931
|
|
|
3745
3932
|
// src/app.js
|
|
@@ -3780,7 +3967,7 @@ var App = class {
|
|
|
3780
3967
|
const { type } = e;
|
|
3781
3968
|
const isDrag = type === "dragover" || type === "dragstart" || type === "dragend" || type === "drop";
|
|
3782
3969
|
const { rootNode: root, maxEventNodeDepth: maxDepth, comps, transactor } = this;
|
|
3783
|
-
const [
|
|
3970
|
+
const [path2, handlers] = DispatchPath.fromNodeAndEventName(
|
|
3784
3971
|
e.target,
|
|
3785
3972
|
type,
|
|
3786
3973
|
root,
|
|
@@ -3788,9 +3975,9 @@ var App = class {
|
|
|
3788
3975
|
comps,
|
|
3789
3976
|
!isDrag
|
|
3790
3977
|
);
|
|
3791
|
-
if (isDrag) this._handleDragEvent(e, type,
|
|
3792
|
-
if (
|
|
3793
|
-
for (const handler of handlers) transactor.transactInputNow(
|
|
3978
|
+
if (isDrag) this._handleDragEvent(e, type, path2);
|
|
3979
|
+
if (path2 !== null && handlers !== null)
|
|
3980
|
+
for (const handler of handlers) transactor.transactInputNow(path2, e, handler, this.dragInfo);
|
|
3794
3981
|
}
|
|
3795
3982
|
_handleTouchEvent(e) {
|
|
3796
3983
|
const { type } = e;
|
|
@@ -3833,7 +4020,7 @@ var App = class {
|
|
|
3833
4020
|
this._touch = null;
|
|
3834
4021
|
}
|
|
3835
4022
|
}
|
|
3836
|
-
_handleDragEvent(e, type,
|
|
4023
|
+
_handleDragEvent(e, type, path2) {
|
|
3837
4024
|
if (type === "dragover") {
|
|
3838
4025
|
const dropTarget = getClosestDropTarget(e.target, this.rootNode, Infinity);
|
|
3839
4026
|
if (dropTarget !== null) {
|
|
@@ -3845,10 +4032,10 @@ var App = class {
|
|
|
3845
4032
|
} else if (type === "dragstart") {
|
|
3846
4033
|
e.target.dataset.dragging = 1;
|
|
3847
4034
|
const rootValue = this.state.val;
|
|
3848
|
-
const txnPath =
|
|
4035
|
+
const txnPath = path2.compact().toTransactionPath();
|
|
3849
4036
|
const value = txnPath.lookup(rootValue);
|
|
3850
4037
|
const dragType = e.target.dataset.dragtype ?? "?";
|
|
3851
|
-
const stack =
|
|
4038
|
+
const stack = path2.buildStack(this.makeStack(rootValue));
|
|
3852
4039
|
this.dragInfo = new DragInfo(stack, value, dragType, e.target);
|
|
3853
4040
|
} else if (type === "drop") {
|
|
3854
4041
|
e.preventDefault();
|
|
@@ -3923,7 +4110,7 @@ var App = class {
|
|
|
3923
4110
|
this.rootNode.removeEventListener(name, this, listenerOpts(name));
|
|
3924
4111
|
}
|
|
3925
4112
|
sendAtRoot(name, args) {
|
|
3926
|
-
this.transactor.pushSend(new
|
|
4113
|
+
this.transactor.pushSend(new DispatchPath(), name, args);
|
|
3927
4114
|
}
|
|
3928
4115
|
registerComponents(comps, opts) {
|
|
3929
4116
|
const scope = this.compStack.enter();
|
|
@@ -4141,7 +4328,20 @@ var WeakMapDomCache = class {
|
|
|
4141
4328
|
};
|
|
4142
4329
|
|
|
4143
4330
|
// src/renderer.js
|
|
4144
|
-
var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
|
|
4331
|
+
var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk", "rp"];
|
|
4332
|
+
function stampRenderBase(vdom, text) {
|
|
4333
|
+
if (vdom instanceof VNode)
|
|
4334
|
+
return new VNode(
|
|
4335
|
+
vdom.tag,
|
|
4336
|
+
{ ...vdom.attrs, "data-rp": text },
|
|
4337
|
+
vdom.childs,
|
|
4338
|
+
vdom.key,
|
|
4339
|
+
vdom.namespace
|
|
4340
|
+
);
|
|
4341
|
+
if (vdom instanceof VFragment)
|
|
4342
|
+
return new VFragment(vdom.childs.map((c) => stampRenderBase(c, text)));
|
|
4343
|
+
return vdom;
|
|
4344
|
+
}
|
|
4145
4345
|
var Renderer = class {
|
|
4146
4346
|
constructor(comps) {
|
|
4147
4347
|
this.comps = comps;
|
|
@@ -4178,17 +4378,17 @@ var Renderer = class {
|
|
|
4178
4378
|
if (comp === null) return null;
|
|
4179
4379
|
return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
|
|
4180
4380
|
}
|
|
4181
|
-
renderIt(stack, node, key, viewName) {
|
|
4381
|
+
renderIt(stack, node, key, viewName, base = null) {
|
|
4182
4382
|
const comp = this.comps.getCompFor(stack.it);
|
|
4183
|
-
return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
|
|
4383
|
+
return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName, base) : null;
|
|
4184
4384
|
}
|
|
4185
4385
|
// `node` is the parse node of the render site (`<x render>` / `render-it` /
|
|
4186
4386
|
// `render-each`, or the view's root anode for the app root). It keys the
|
|
4187
4387
|
// cache as a globally-unique object: node ids alone are unique only within a
|
|
4188
4388
|
// single view, so the same value rendered by two components (e.g. through a
|
|
4189
4389
|
// shared dynamic-var sequence) would otherwise collide in the cache.
|
|
4190
|
-
_rValComp(stack, val, comp, node, key, viewName) {
|
|
4191
|
-
const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
|
|
4390
|
+
_rValComp(stack, val, comp, node, key, viewName, base = null) {
|
|
4391
|
+
const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}${stack.renderPath.addressKey}`;
|
|
4192
4392
|
const cachePath = [node, val];
|
|
4193
4393
|
stack._pushDynBindValuesToArray(cachePath, comp);
|
|
4194
4394
|
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
@@ -4196,30 +4396,43 @@ var Renderer = class {
|
|
|
4196
4396
|
const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
|
|
4197
4397
|
const body = this.renderView(view, stack);
|
|
4198
4398
|
if (body == null) return null;
|
|
4399
|
+
const baseJson = base === null ? null : pathToJson(base);
|
|
4199
4400
|
const meta = this._renderMetadata({
|
|
4200
4401
|
$: "Comp",
|
|
4201
4402
|
nid: node?.nodeId ?? null,
|
|
4202
4403
|
cid: comp.id,
|
|
4203
|
-
vid: view.name
|
|
4404
|
+
vid: view.name,
|
|
4405
|
+
...baseJson === null ? null : { base: baseJson }
|
|
4204
4406
|
});
|
|
4205
|
-
const dom = new VFragment([
|
|
4407
|
+
const dom = new VFragment([
|
|
4408
|
+
meta,
|
|
4409
|
+
baseJson === null ? body : stampRenderBase(body, JSON.stringify(baseJson))
|
|
4410
|
+
]);
|
|
4206
4411
|
this.cache.set(cachePath, cacheKey, dom);
|
|
4207
4412
|
return dom;
|
|
4208
4413
|
}
|
|
4209
4414
|
pushEachEntry(r, nid, attrName, key, dom) {
|
|
4210
4415
|
r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
|
|
4211
4416
|
}
|
|
4212
|
-
renderEachWhen(stack,
|
|
4417
|
+
renderEachWhen(stack, each) {
|
|
4418
|
+
const { iterInfo, node: view, nodeId: nid } = each;
|
|
4213
4419
|
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
4420
|
+
const seqPath = iterInfo.val instanceof DynVal ? stack.lookupDynamicLocated(iterInfo.val.name)?.path ?? null : null;
|
|
4214
4421
|
const r = [];
|
|
4215
4422
|
const it = stack.it;
|
|
4216
4423
|
const renderOne = (key, value, attrName, binds) => {
|
|
4424
|
+
const itemBase = seqPath === null ? null : keyedPath(seqPath, key);
|
|
4425
|
+
const itemStep = itemBase === null ? each.itemStep(key) : null;
|
|
4426
|
+
const itemPath = itemBase !== null ? stack.renderPath.pushFrame(itemBase) : itemStep !== null ? stack.renderPath.pushItem(itemStep) : stack.renderPath;
|
|
4217
4427
|
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
4218
|
-
const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
|
|
4428
|
+
const cacheKey = `${stack.viewsId ?? ""}${nid}${key}${itemPath.addressKey}`;
|
|
4219
4429
|
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
4220
4430
|
if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
4221
4431
|
else {
|
|
4222
|
-
const dom = this.renderView(
|
|
4432
|
+
const dom = this.renderView(
|
|
4433
|
+
view,
|
|
4434
|
+
stack.enter(value, binds, false, itemPath, itemBase !== null)
|
|
4435
|
+
);
|
|
4223
4436
|
if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
|
|
4224
4437
|
this.cache.set(cachePath, cacheKey, dom);
|
|
4225
4438
|
}
|
|
@@ -4331,6 +4544,7 @@ export {
|
|
|
4331
4544
|
html,
|
|
4332
4545
|
injectCss,
|
|
4333
4546
|
macro,
|
|
4547
|
+
path,
|
|
4334
4548
|
phaseOps,
|
|
4335
4549
|
resolveArgs,
|
|
4336
4550
|
rootDispatcher,
|