tutuca 0.14.0 → 0.15.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.
@@ -209,12 +209,6 @@ enableMapSet();
209
209
 
210
210
  // src/path.js
211
211
  var NONE = /* @__PURE__ */ Symbol("NONE");
212
- var readKey = (value, key, dval = null) => {
213
- if (value == null) return dval;
214
- if (value instanceof Map) return value.has(key) ? value.get(key) : dval;
215
- if (value instanceof Set) return value.has(key) ? key : dval;
216
- return Object.hasOwn(value, key) ? value[key] : dval;
217
- };
218
212
  var writeKey = (value, key, next) => {
219
213
  if (value instanceof Map) value.set(key, next);
220
214
  else if (value instanceof Set) {
@@ -222,16 +216,8 @@ var writeKey = (value, key, next) => {
222
216
  value.add(next);
223
217
  } else value[key] = next;
224
218
  };
225
- var writeSeqKey = (value, key, next) => {
226
- if (value instanceof Map || value instanceof Set || Array.isArray(value) || Object.hasOwn(value, key))
227
- writeKey(value, key, next);
228
- else if (typeof value?.set === "function") value.set(key, next);
229
- else writeKey(value, key, next);
230
- };
219
+ var writeSeqKey = (value, key, next) => !(value instanceof Map || value instanceof Set || Array.isArray(value)) && !Object.hasOwn(value, key) && typeof value?.set === "function" ? value.set(key, next) : writeKey(value, key, next);
231
220
  var Step = class {
232
- lookup(_v, dval = null) {
233
- return dval;
234
- }
235
221
  setDraftValue(_root, _v) {
236
222
  }
237
223
  // Re-enter this step while rebuilding a stack. `renderPath` is the dispatch
@@ -255,28 +241,22 @@ var Step = class {
255
241
  return null;
256
242
  }
257
243
  };
258
- var BindStep = class _BindStep extends Step {
244
+ var BindStep = class extends Step {
259
245
  constructor(binds) {
260
246
  super();
261
247
  this.binds = binds;
262
248
  }
263
- lookup(v, _dval) {
249
+ lookup(v) {
264
250
  return v;
265
251
  }
266
252
  enterFrame(stack, next, renderPath) {
267
253
  return stack.enter(next, { ...this.binds }, false, renderPath);
268
254
  }
269
- withIndex(i) {
270
- return new _BindStep({ ...this.binds, key: i });
271
- }
272
- withKey(key) {
273
- return new _BindStep({ ...this.binds, key });
274
- }
275
255
  toAbstractPathStep() {
276
256
  return null;
277
257
  }
278
258
  };
279
- var ScopeBindStep = class _ScopeBindStep extends BindStep {
259
+ var ScopeBindStep = class extends BindStep {
280
260
  constructor(val, binds = {}) {
281
261
  super(binds);
282
262
  this.val = val;
@@ -285,30 +265,18 @@ var ScopeBindStep = class _ScopeBindStep extends BindStep {
285
265
  const dyn = this.val.evalAsHandler(stack)?.call(stack.it) ?? {};
286
266
  return stack.enter(next, { ...this.binds, ...dyn }, false, renderPath);
287
267
  }
288
- withIndex(i) {
289
- return new _ScopeBindStep(this.val, { ...this.binds, key: i });
290
- }
291
- withKey(key) {
292
- return new _ScopeBindStep(this.val, { ...this.binds, key });
293
- }
294
268
  };
295
269
  var FieldStep = class extends Step {
296
270
  constructor(field) {
297
271
  super();
298
272
  this.field = field;
299
273
  }
300
- lookup(v, dval = null) {
301
- return readKey(v, this.field, dval);
274
+ lookup(v) {
275
+ return seqGet(v, this.field, NONE);
302
276
  }
303
277
  setDraftValue(root, v) {
304
278
  writeKey(root, this.field, v);
305
279
  }
306
- withIndex(i) {
307
- return new SeqStep(this.field, i);
308
- }
309
- withKey(k) {
310
- return new SeqStep(this.field, k);
311
- }
312
280
  toKey() {
313
281
  return { field: this.field };
314
282
  }
@@ -319,11 +287,11 @@ var SeqStep = class extends Step {
319
287
  this.field = field;
320
288
  this.key = key;
321
289
  }
322
- lookup(v, dval = null) {
323
- return seqGet(readKey(v, this.field, null), this.key, dval);
290
+ lookup(v) {
291
+ return seqGet(seqGet(v, this.field, null), this.key, NONE);
324
292
  }
325
293
  setDraftValue(root, v) {
326
- const seq = readKey(root, this.field, null);
294
+ const seq = seqGet(root, this.field, null);
327
295
  if (seq != null) writeSeqKey(seq, this.key, v);
328
296
  }
329
297
  enterFrame(stack, next, renderPath) {
@@ -339,20 +307,20 @@ var SeqAccessStep = class extends Step {
339
307
  this.seqField = seqField;
340
308
  this.keyField = keyField;
341
309
  }
342
- lookup(v, dval = null) {
343
- const seq = readKey(v, this.seqField, NONE);
344
- const key = readKey(v, this.keyField, NONE);
345
- return key !== NONE && seq !== NONE ? seqGet(seq, key, dval) : dval;
310
+ lookup(v) {
311
+ const seq = seqGet(v, this.seqField, NONE);
312
+ const key = seqGet(v, this.keyField, NONE);
313
+ return key !== NONE && seq !== NONE ? seqGet(seq, key, NONE) : NONE;
346
314
  }
347
315
  setDraftValue(root, v) {
348
- const seq = readKey(root, this.seqField, NONE);
349
- const key = readKey(root, this.keyField, NONE);
316
+ const seq = seqGet(root, this.seqField, NONE);
317
+ const key = seqGet(root, this.keyField, NONE);
350
318
  if (seq !== NONE && key !== NONE) writeSeqKey(seq, key, v);
351
319
  }
352
320
  // Resolve `keyField` against `v` now and freeze it as a literal-key `SeqStep`, so a
353
321
  // later lookup/setValue lands on this same item even if `keyField` changes meanwhile.
354
322
  pinKey(v) {
355
- const key = readKey(v, this.keyField, NONE);
323
+ const key = seqGet(v, this.keyField, NONE);
356
324
  return key === NONE ? this : new SeqStep(this.seqField, key);
357
325
  }
358
326
  // The key is a *field reference* resolved live, so it is unknown without a value;
@@ -363,18 +331,18 @@ var SeqAccessStep = class extends Step {
363
331
  }
364
332
  };
365
333
  var EachBindStep = class extends Step {
366
- constructor(iterInfo, key) {
334
+ constructor(eachNode, key) {
367
335
  super();
368
- this.iterInfo = iterInfo;
336
+ this.eachNode = eachNode;
369
337
  this.key = key;
370
338
  }
371
- lookup(v, _dval) {
339
+ lookup(v) {
372
340
  return v;
373
341
  }
374
342
  // Replay the renderer's per-item binds (key, value + any @enrich-with binds)
375
343
  // so a rebuilt stack matches the one @each rendered with.
376
344
  enterFrame(stack, next, renderPath) {
377
- return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false, renderPath);
345
+ return stack.enter(next, this.eachNode.enrichBinds(stack, this.key), false, renderPath);
378
346
  }
379
347
  toAbstractPathStep() {
380
348
  return null;
@@ -426,9 +394,6 @@ var Path = class _Path {
426
394
  concat(steps) {
427
395
  return new _Path(this.steps.concat(steps));
428
396
  }
429
- popStep() {
430
- return new _Path(this.steps.slice(0, -1));
431
- }
432
397
  // Frame-only steps removed, one step per crossed component: `popStep` over the
433
398
  // result bubbles through every component.
434
399
  compact() {
@@ -450,7 +415,7 @@ var Path = class _Path {
450
415
  const step = this.steps[i];
451
416
  const pinned = step.pinKey(curVal);
452
417
  if (pinned !== step) (out ??= this.steps.slice())[i] = pinned;
453
- curVal = step.lookup(curVal, NONE);
418
+ curVal = step.lookup(curVal);
454
419
  if (curVal === NONE) break;
455
420
  }
456
421
  return out ? new _Path(out) : this;
@@ -458,7 +423,7 @@ var Path = class _Path {
458
423
  lookup(v, dval = null) {
459
424
  let curVal = v;
460
425
  for (const step of this.steps) {
461
- curVal = step.lookup(curVal, NONE);
426
+ curVal = step.lookup(curVal);
462
427
  if (curVal === NONE) return dval;
463
428
  }
464
429
  return curVal;
@@ -471,7 +436,7 @@ var Path = class _Path {
471
436
  const out = [root];
472
437
  let curVal = root;
473
438
  for (const step of this.steps) {
474
- curVal = step.lookup(curVal, NONE);
439
+ curVal = step.lookup(curVal);
475
440
  if (curVal === NONE) break;
476
441
  out.push(curVal);
477
442
  }
@@ -494,20 +459,17 @@ var Path = class _Path {
494
459
  return (0, immer_exports.produce)(root, (draft) => {
495
460
  let parent = draft;
496
461
  for (let i = 0; i < this.steps.length - 1; i++) {
497
- parent = this.steps[i].lookup(parent, NONE);
462
+ parent = this.steps[i].lookup(parent);
498
463
  if (parent === NONE) return;
499
464
  }
500
465
  this.steps.at(-1).setDraftValue(parent, v);
501
466
  });
502
467
  }
503
- buildStack(stack) {
504
- return walkItems(stack, this.steps, stack.renderPath ?? new DispatchPath(), this)?.[0] ?? null;
505
- }
506
468
  };
507
469
  function walkItems(stack, items, renderPath, path2) {
508
470
  let prev = stack.it;
509
471
  for (const step of items) {
510
- const next = step.lookup(prev, NONE);
472
+ const next = step.lookup(prev);
511
473
  if (next === NONE) {
512
474
  console.warn("bad PathItem", { root: stack.it, step, path: path2 });
513
475
  return null;
@@ -537,7 +499,6 @@ var DispatchPath = class _DispatchPath {
537
499
  return new _DispatchPath(frames);
538
500
  }
539
501
  concat(steps) {
540
- if (this.frames.length === 0) return _DispatchPath.ofSteps(steps);
541
502
  return this._withTopItems(this.top.items.concat(steps));
542
503
  }
543
504
  pushItem(step) {
@@ -547,23 +508,17 @@ var DispatchPath = class _DispatchPath {
547
508
  return new _DispatchPath(this.frames.concat({ base, items: [] }));
548
509
  }
549
510
  // Whether bubbling has anywhere left to go: another step in this frame, or a
550
- // visual caller underneath it.
511
+ // visual caller underneath it. (A path always has at least one frame.)
551
512
  canPop() {
552
- const n = this.frames.length;
553
- return n > 1 || n === 1 && this.frames[0].items.length > 0;
554
- }
555
- isRoot() {
556
- return this.toTransactionPath().steps.length === 0;
513
+ return this.frames.length > 1 || this.frames[0].items.length > 0;
557
514
  }
558
515
  // One component closer to the root. At the top of a frame that is popping back
559
516
  // to the visual caller, not to the producer's own parent — the caller is where
560
517
  // the `*name` was written, and where an unhandled message should keep going.
561
518
  popStep() {
562
- const n = this.frames.length;
563
- if (n === 0) return this;
564
- const top = this.frames[n - 1];
519
+ const { top } = this;
565
520
  if (top.items.length > 0) return this._withTopItems(top.items.slice(0, -1));
566
- if (n > 1) return new _DispatchPath(this.frames.slice(0, -1));
521
+ if (this.frames.length > 1) return new _DispatchPath(this.frames.slice(0, -1));
567
522
  return this;
568
523
  }
569
524
  // Drop frame-only steps inside every frame independently; a frame's base is
@@ -585,8 +540,8 @@ var DispatchPath = class _DispatchPath {
585
540
  // The active transaction address: the top frame's absolute base followed by
586
541
  // its ordinary descendant steps. This is where a mutation lands.
587
542
  toTransactionPath() {
588
- const top = this.top;
589
- return top === void 0 ? EMPTY_PATH : top.base.concat(top.items);
543
+ const { base, items } = this.top;
544
+ return base.concat(items);
590
545
  }
591
546
  // Rebuild the render stack this path was dispatched from. A frame with a base
592
547
  // re-enters at that absolute value first — replaying the resume a `*name`
@@ -610,10 +565,12 @@ var DispatchPath = class _DispatchPath {
610
565
  }
611
566
  return stack;
612
567
  }
613
- static fromNodeAndEventName(node, eventName, rootNode, maxDepth, comps, stopOnNoEvent = true) {
568
+ // Reconstruct the dispatch position of a DOM event from the `data-*` stamps and
569
+ // `§…§` meta comments the renderer left on the way down. `stopOnNoEvent` is off for
570
+ // drag events, whose path is needed even where no handler is registered.
571
+ static fromNodeAndEventName(node, eventName, rootNode, comps, stopOnNoEvent = true) {
614
572
  const parts = [];
615
573
  const bubbles = BUBBLING_EVENTS.has(eventName);
616
- let depth = 0;
617
574
  let eventIds = [];
618
575
  let handlers = null;
619
576
  let nodeRefs = [];
@@ -639,7 +596,7 @@ var DispatchPath = class _DispatchPath {
639
596
  nodeRefs = [];
640
597
  return true;
641
598
  };
642
- while (node && node !== rootNode && depth < maxDepth) {
599
+ while (node && node !== rootNode) {
643
600
  if (node?.dataset) {
644
601
  const { eid, cid, vid, rp } = node.dataset;
645
602
  if (eid !== void 0) eventIds.push(eid);
@@ -662,7 +619,6 @@ var DispatchPath = class _DispatchPath {
662
619
  }
663
620
  }
664
621
  }
665
- depth += 1;
666
622
  node = node.parentNode;
667
623
  }
668
624
  parts.reverse();
@@ -734,13 +690,6 @@ var StepCtx = class _StepCtx {
734
690
  resolveNode() {
735
691
  return this.comp.getNodeForId(+this.meta.nid, this.vid);
736
692
  }
737
- applyKey(pi) {
738
- if (pi === null) return null;
739
- const m = this.meta;
740
- if (m.si !== void 0) return pi.withIndex(+m.si);
741
- if (m.sk !== void 0) return pi.withKey(m.sk);
742
- return pi;
743
- }
744
693
  };
745
694
  function resolvePathPart(comp, nodeRefs, vid) {
746
695
  for (let i = 0; i < nodeRefs.length; i++) {
@@ -778,10 +727,8 @@ var PathBuilder = class {
778
727
  }
779
728
  };
780
729
 
781
- // src/util/env.js
782
- var isMac = (globalThis.navigator?.userAgent ?? "").toLowerCase().includes("mac");
783
-
784
730
  // src/value.js
731
+ var isMac = (globalThis.navigator?.userAgent ?? "").toLowerCase().includes("mac");
785
732
  var VALID_VAL_ID_RE = /^[a-zA-Z][a-zA-Z0-9_]*\??$/;
786
733
  var isValidValId = (name) => VALID_VAL_ID_RE.test(name);
787
734
  var VALID_FLOAT_RE = /^-?[0-9]+(\.[0-9]+)?$/;
@@ -963,22 +910,10 @@ function _parsePredicate(s, tokens, px) {
963
910
  }
964
911
  return new PredicateVal(pred, args);
965
912
  }
966
- function kindOf(val) {
967
- if (val === null) return 0;
968
- if (val instanceof ConstVal) return val.kind;
969
- if (val instanceof StrTplVal) return val.kind;
970
- if (val instanceof SeqAccessVal) return K_SEQ;
971
- if (val instanceof FieldVal) return K_FIELD;
972
- if (val instanceof MethodVal) return K_METHOD;
973
- if (val instanceof BindVal) return K_BIND;
974
- if (val instanceof DynVal) return K_DYN;
975
- if (val instanceof NameVal) return K_NAME;
976
- if (val instanceof EventMemberVal) return K_EVENT;
977
- return 0;
978
- }
913
+ var kindOf = (val) => val?.kind ?? 0;
979
914
  var BaseVal = class {
980
- render(_stack, _rx) {
981
- }
915
+ // No kind: never accepted by a group (PredicateVal, which only parseBool builds).
916
+ kind = 0;
982
917
  eval(_stack) {
983
918
  }
984
919
  toPathItem() {
@@ -998,9 +933,6 @@ var ConstVal = class extends BaseVal {
998
933
  this.val = val;
999
934
  this.kind = kind;
1000
935
  }
1001
- render(_stack, _rx) {
1002
- return this.val;
1003
- }
1004
936
  eval(_stack) {
1005
937
  return this.val;
1006
938
  }
@@ -1026,9 +958,7 @@ var PredicateVal = class extends BaseVal {
1026
958
  return `${this.pred.name} ${this.args.map(String).join(" ")}`;
1027
959
  }
1028
960
  };
1029
- var VarVal = class extends BaseVal {
1030
- };
1031
- var StrTplVal = class _StrTplVal extends VarVal {
961
+ var StrTplVal = class _StrTplVal extends BaseVal {
1032
962
  constructor(vals) {
1033
963
  super();
1034
964
  this.vals = vals;
@@ -1041,9 +971,6 @@ var StrTplVal = class _StrTplVal extends VarVal {
1041
971
  for (const v of this.vals) if (!(v instanceof ConstVal) || v.fromMacroVar) return false;
1042
972
  return true;
1043
973
  }
1044
- render(stack, _rx) {
1045
- return this.eval(stack);
1046
- }
1047
974
  eval(stack) {
1048
975
  const strs = new Array(this.vals.length);
1049
976
  for (let i = 0; i < this.vals.length; i++) strs[i] = this.vals[i]?.eval(stack, "");
@@ -1080,7 +1007,8 @@ var StrTplVal = class _StrTplVal extends VarVal {
1080
1007
  return new _StrTplVal(lo === 0 && hi === vals.length ? vals : vals.slice(lo, hi));
1081
1008
  }
1082
1009
  };
1083
- var NameVal = class extends VarVal {
1010
+ var NameVal = class extends BaseVal {
1011
+ kind = K_NAME;
1084
1012
  constructor(name) {
1085
1013
  super();
1086
1014
  this.name = name;
@@ -1130,6 +1058,7 @@ var EVENT_CONVENIENCES = {
1130
1058
  dragKey: nullSafe((info) => info.lookupBind("key"))
1131
1059
  };
1132
1060
  var EventMemberVal = class extends BaseVal {
1061
+ kind = K_EVENT;
1133
1062
  constructor(members) {
1134
1063
  super();
1135
1064
  this.members = members;
@@ -1152,24 +1081,21 @@ var EventMemberVal = class extends BaseVal {
1152
1081
  return `e.${this.members.join(".")}`;
1153
1082
  }
1154
1083
  };
1155
- var RenderVal = class extends BaseVal {
1156
- render(stack, _rx) {
1157
- return this.eval(stack);
1158
- }
1159
- };
1160
- var RenderNameVal = class extends RenderVal {
1084
+ var SigilNameVal = class extends BaseVal {
1161
1085
  constructor(name) {
1162
1086
  super();
1163
1087
  this.name = name;
1164
1088
  }
1089
+ toString() {
1090
+ return this.sigil + this.name;
1091
+ }
1165
1092
  };
1166
- var BindVal = class extends RenderNameVal {
1093
+ var BindVal = class extends SigilNameVal {
1094
+ kind = K_BIND;
1095
+ sigil = "@";
1167
1096
  eval(stack) {
1168
1097
  return stack.lookupBind(this.name);
1169
1098
  }
1170
- toString() {
1171
- return `@${this.name}`;
1172
- }
1173
1099
  };
1174
1100
  var BindMemberVal = class extends BindVal {
1175
1101
  constructor(name, member) {
@@ -1184,37 +1110,35 @@ var BindMemberVal = class extends BindVal {
1184
1110
  return `@${this.name}.${this.member}`;
1185
1111
  }
1186
1112
  };
1187
- var DynVal = class extends RenderNameVal {
1113
+ var DynVal = class extends SigilNameVal {
1114
+ kind = K_DYN;
1115
+ sigil = "*";
1188
1116
  eval(stack) {
1189
1117
  return stack.lookupDynamic(this.name);
1190
1118
  }
1191
- toString() {
1192
- return `*${this.name}`;
1193
- }
1194
1119
  };
1195
- var FieldVal = class extends RenderNameVal {
1120
+ var FieldVal = class extends SigilNameVal {
1121
+ kind = K_FIELD;
1122
+ sigil = ".";
1196
1123
  eval(stack) {
1197
1124
  return stack.lookupFieldRaw(this.name);
1198
1125
  }
1199
1126
  toPathItem() {
1200
1127
  return new FieldStep(this.name);
1201
1128
  }
1202
- toString() {
1203
- return `.${this.name}`;
1204
- }
1205
1129
  };
1206
- var MethodVal = class extends RenderNameVal {
1130
+ var MethodVal = class extends SigilNameVal {
1131
+ kind = K_METHOD;
1132
+ sigil = "$";
1207
1133
  eval(stack) {
1208
1134
  return stack.lookupMethod(this.name);
1209
1135
  }
1210
1136
  evalAsHandler(stack) {
1211
1137
  return stack.lookupFieldRaw(this.name);
1212
1138
  }
1213
- toString() {
1214
- return `$${this.name}`;
1215
- }
1216
1139
  };
1217
- var SeqAccessVal = class extends RenderVal {
1140
+ var SeqAccessVal = class extends BaseVal {
1141
+ kind = K_SEQ;
1218
1142
  constructor(seqVal, keyVal) {
1219
1143
  super();
1220
1144
  this.seqVal = seqVal;
@@ -1237,9 +1161,6 @@ var Attributes = class {
1237
1161
  constructor(items) {
1238
1162
  this.items = items;
1239
1163
  }
1240
- static parse(attributes, px, parseAll = false) {
1241
- return new AttrParser(px).parse(attributes, parseAll);
1242
- }
1243
1164
  isConstant() {
1244
1165
  return false;
1245
1166
  }
@@ -1257,10 +1178,16 @@ function parseDirectiveValue(px, directiveName, source, parser) {
1257
1178
  }
1258
1179
  return val;
1259
1180
  }
1181
+ var ITER_DIRECTIVES = {
1182
+ when: "whenVal",
1183
+ "loop-with": "loopWithVal",
1184
+ "enrich-with": "enrichWithVal"
1185
+ };
1186
+ var parseIterDirective = (px, name, s) => parseDirectiveValue(px, name, s, parseAlterHandler);
1260
1187
  function parseIterationDirectives(attributes, px) {
1261
1188
  const parseNamed = (name) => {
1262
1189
  const attr = attributes.getNamedItem(`@${name}`);
1263
- return attr ? parseDirectiveValue(px, name, attr.value, parseAlterHandler) : null;
1190
+ return attr ? parseIterDirective(px, name, attr.value) : null;
1264
1191
  };
1265
1192
  return { whenVal: parseNamed("when"), loopWithVal: parseNamed("loop-with") };
1266
1193
  }
@@ -1301,11 +1228,22 @@ var AttrParser = class {
1301
1228
  this.px.onParseIssue("bad-value", info);
1302
1229
  }
1303
1230
  }
1304
- parseThen(s) {
1305
- if (this.ifAttr) this.ifAttr.thenVal = parseText(s, this.px) ?? NOT_SET_VAL;
1231
+ // `@then` / `@else` fill the branches of the `@if.<attr>` on the same element.
1232
+ parseBranch(slot, name, s) {
1233
+ if (this.ifAttr === null) return this._orphan(name, s, "if");
1234
+ this.ifAttr[slot] = parseText(s, this.px) ?? NOT_SET_VAL;
1235
+ }
1236
+ // `@when` / `@loop-with` / `@enrich-with` amend the `@each` on the same element. A
1237
+ // loop-less `@enrich-with` is a scope of its own; the other two need the loop.
1238
+ parseIter(name, s) {
1239
+ const val = parseIterDirective(this.px, name, s);
1240
+ if (this.eachAttr !== null) this.eachAttr[ITER_DIRECTIVES[name]] = val;
1241
+ else if (name === "enrich-with") this.pushWrapper("scope", s, val);
1242
+ else this._orphan(name, s, "each");
1306
1243
  }
1307
- parseElse(value) {
1308
- if (this.ifAttr) this.ifAttr.elseVal = parseText(value, this.px) ?? NOT_SET_VAL;
1244
+ // A directive that only means something next to another one, written alone.
1245
+ _orphan(name, value, needs) {
1246
+ this.px.onParseIssue("orphan-directive", { name, value, needs });
1309
1247
  }
1310
1248
  parseEvent(directiveName, value) {
1311
1249
  const [eventName, ...modifiers] = directiveName.slice(3).split("+");
@@ -1319,77 +1257,51 @@ var AttrParser = class {
1319
1257
  this.events.add(eventName, handler, modifiers);
1320
1258
  }
1321
1259
  }
1322
- _parseDirectiveValue(directiveName, s, parserFn) {
1323
- return parseDirectiveValue(this.px, directiveName, s, parserFn);
1324
- }
1325
1260
  parseDirective(s, directiveName) {
1326
1261
  switch (directiveName) {
1327
1262
  case "dangerouslysetinnerhtml":
1328
1263
  this.attrs ??= [];
1329
- this.attrs.push(new RawHtmlAttr(this._parseDirectiveValue(directiveName, s, parseText)));
1264
+ this.attrs.push(new RawHtmlAttr(parseDirectiveValue(this.px, directiveName, s, parseText)));
1330
1265
  this.hasDynamic = true;
1331
1266
  return;
1332
1267
  case "push-view":
1333
- this.pushWrapper("push-view", s, this._parseDirectiveValue(directiveName, s, parseText));
1268
+ this.pushWrapper("push-view", s, parseDirectiveValue(this.px, directiveName, s, parseText));
1334
1269
  return;
1335
1270
  case "text":
1336
- this.textChild = this._parseDirectiveValue(directiveName, s, parseText);
1271
+ this.textChild = parseDirectiveValue(this.px, directiveName, s, parseText);
1337
1272
  return;
1338
1273
  case "show":
1339
- this.pushWrapper("show", s, this._parseDirectiveValue(directiveName, s, parseBool));
1274
+ this.pushWrapper("show", s, parseDirectiveValue(this.px, directiveName, s, parseBool));
1340
1275
  return;
1341
1276
  case "hide":
1342
- this.pushWrapper("hide", s, this._parseDirectiveValue(directiveName, s, parseBool));
1277
+ this.pushWrapper("hide", s, parseDirectiveValue(this.px, directiveName, s, parseBool));
1343
1278
  return;
1344
1279
  case "each": {
1345
- const val = this._parseDirectiveValue(directiveName, s, parseSequence);
1280
+ const val = parseDirectiveValue(this.px, directiveName, s, parseSequence);
1346
1281
  this.eachAttr = this.pushWrapper("each", s, val);
1347
1282
  return;
1348
1283
  }
1349
- case "enrich-with":
1350
- if (this.eachAttr !== null)
1351
- this.eachAttr.enrichWithVal = this._parseDirectiveValue(
1352
- directiveName,
1353
- s,
1354
- parseAlterHandler
1355
- );
1356
- else
1357
- this.pushWrapper(
1358
- "scope",
1359
- s,
1360
- this._parseDirectiveValue(directiveName, s, parseAlterHandler)
1361
- );
1362
- return;
1363
1284
  case "when":
1364
- this._parseWhen(s);
1365
- return;
1366
1285
  case "loop-with":
1367
- this._parseLoopWith(s);
1286
+ case "enrich-with":
1287
+ this.parseIter(directiveName, s);
1368
1288
  return;
1369
1289
  case "then":
1370
- this.parseThen(s);
1290
+ this.parseBranch("thenVal", directiveName, s);
1371
1291
  return;
1372
1292
  case "else":
1373
- this.parseElse(s);
1293
+ this.parseBranch("elseVal", directiveName, s);
1374
1294
  return;
1375
1295
  }
1376
1296
  if (directiveName.startsWith("on.")) this.parseEvent(directiveName, s);
1377
1297
  else if (directiveName.startsWith("if.")) this.parseIf(directiveName, s);
1378
- else if (directiveName.startsWith("then.")) this.parseThen(s);
1379
- else if (directiveName.startsWith("else.")) this.parseElse(s);
1298
+ else if (directiveName.startsWith("then.")) this.parseBranch("thenVal", directiveName, s);
1299
+ else if (directiveName.startsWith("else.")) this.parseBranch("elseVal", directiveName, s);
1380
1300
  else {
1381
1301
  const info = { name: directiveName, value: s };
1382
1302
  this.px.onParseIssue("unknown-directive", info);
1383
1303
  }
1384
1304
  }
1385
- _parseWhen(s) {
1386
- if (this.eachAttr !== null)
1387
- this.eachAttr.whenVal = this._parseDirectiveValue("when", s, parseAlterHandler);
1388
- }
1389
- _parseLoopWith(s) {
1390
- if (this.eachAttr !== null)
1391
- this.eachAttr.loopWithVal = this._parseDirectiveValue("loop-with", s, parseAlterHandler);
1392
- }
1393
1305
  parse(attributes, parseAll = false) {
1394
1306
  for (const { name, value } of attributes) {
1395
1307
  const charCode = name.charCodeAt(0);
@@ -1742,19 +1654,21 @@ var VNode = class _VNode extends VBase {
1742
1654
  const createOpts = attrs.is != null ? { is: attrs.is } : void 0;
1743
1655
  const node = ns === null ? doc.createElement(tag, createOpts) : doc.createElementNS(ns, tag, createOpts);
1744
1656
  const cOpts = childOpts(this, ns, opts);
1745
- if ("value" in attrs || "checked" in attrs) {
1746
- const { value, checked, ...rest } = attrs;
1747
- applyProperties(node, rest);
1748
- appendChildNodes(node, this.childs, cOpts);
1749
- if (value !== void 0) applyValueLast(node, value);
1750
- if (checked !== void 0) setProp(node, "checked", checked, false);
1751
- } else {
1752
- applyProperties(node, attrs);
1753
- appendChildNodes(node, this.childs, cOpts);
1754
- }
1657
+ applyAttrs(node, attrs, () => appendChildNodes(node, this.childs, cOpts));
1755
1658
  return node;
1756
1659
  }
1757
1660
  };
1661
+ function applyAttrs(node, attrs, placeChildren) {
1662
+ const hasValue = "value" in attrs;
1663
+ const hasChecked = "checked" in attrs;
1664
+ if (hasValue || hasChecked) {
1665
+ const { value: _v, checked: _c, ...rest } = attrs;
1666
+ applyProperties(node, rest);
1667
+ } else applyProperties(node, attrs);
1668
+ placeChildren();
1669
+ if (hasValue) applyValueLast(node, attrs.value);
1670
+ if (hasChecked) setProp(node, "checked", attrs.checked, isNamespaced(node));
1671
+ }
1758
1672
  function diffProps(a, b) {
1759
1673
  if (a === b) return null;
1760
1674
  let diff = null;
@@ -1785,22 +1699,16 @@ function morphNode(domNode, source, target, opts) {
1785
1699
  }
1786
1700
  if (type === 1 && source.isSameKind(target)) {
1787
1701
  const propsDiff = diffProps(source.attrs, target.attrs);
1788
- const hasValue = propsDiff != null && "value" in propsDiff;
1789
- const hasChecked = propsDiff != null && "checked" in propsDiff;
1790
- if (propsDiff) {
1791
- if (hasValue || hasChecked) {
1792
- const { value: _v, checked: _c, ...rest } = propsDiff;
1793
- applyProperties(domNode, rest);
1794
- } else applyProperties(domNode, propsDiff);
1795
- }
1796
- if (!target.attrs.dangerouslySetInnerHTML) {
1702
+ const placeChildren = () => {
1703
+ if (target.attrs.dangerouslySetInnerHTML) return;
1797
1704
  const ns = effectiveNs(target, opts);
1798
1705
  morphChildren(domNode, source.childs, target.childs, childOpts(target, ns, opts));
1706
+ };
1707
+ if (propsDiff) applyAttrs(domNode, propsDiff, placeChildren);
1708
+ else placeChildren();
1709
+ if (!(propsDiff && "value" in propsDiff) && source.tag === "SELECT") {
1710
+ if (target.attrs.value !== void 0) applyValueLast(domNode, target.attrs.value);
1799
1711
  }
1800
- if (hasValue) applyValueLast(domNode, propsDiff.value);
1801
- else if (source.tag === "SELECT" && target.attrs.value !== void 0)
1802
- applyValueLast(domNode, target.attrs.value);
1803
- if (hasChecked) setProp(domNode, "checked", propsDiff.checked, false);
1804
1712
  return domNode;
1805
1713
  }
1806
1714
  if (type === 11) {
@@ -1934,8 +1842,11 @@ var BaseNode = class {
1934
1842
  render(_stack, _rx) {
1935
1843
  return null;
1936
1844
  }
1937
- setDataAttr(key, val) {
1938
- console.warn("setDataAttr not implemented for", this, { key, val });
1845
+ // Stamp a `data-*` attribute on the element(s) this node renders. A no-op for
1846
+ // nodes that produce no element of their own (text, `<x render*>`): a view whose
1847
+ // root is one of those records its component boundary in the `§Comp§` meta
1848
+ // comment instead (see Renderer._rValComp).
1849
+ setDataAttr(_key, _val) {
1939
1850
  }
1940
1851
  isConstant() {
1941
1852
  return false;
@@ -1974,21 +1885,12 @@ var TextNode = class extends BaseNode {
1974
1885
  isConstant() {
1975
1886
  return true;
1976
1887
  }
1977
- setDataAttr(_key, _val) {
1978
- }
1979
1888
  };
1980
1889
  var CommentNode = class extends TextNode {
1981
1890
  render(_stack, rx) {
1982
1891
  return rx.renderComment(this.val);
1983
1892
  }
1984
1893
  };
1985
- function optimizeChilds(childs) {
1986
- for (let i = 0; i < childs.length; i++) {
1987
- const child = childs[i];
1988
- if (child.isConstant()) childs[i] = new RenderOnceNode(child);
1989
- else child.optimize();
1990
- }
1991
- }
1992
1894
  function optimizeNode(node) {
1993
1895
  if (node.isConstant()) return new RenderOnceNode(node);
1994
1896
  node.optimize();
@@ -2003,7 +1905,8 @@ var ChildsNode = class extends BaseNode {
2003
1905
  return this.childs.every((v) => v.isConstant());
2004
1906
  }
2005
1907
  optimize() {
2006
- optimizeChilds(this.childs);
1908
+ const { childs } = this;
1909
+ for (let i = 0; i < childs.length; i++) childs[i] = optimizeNode(childs[i]);
2007
1910
  }
2008
1911
  };
2009
1912
  var DomNode = class extends ChildsNode {
@@ -2015,8 +1918,7 @@ var DomNode = class extends ChildsNode {
2015
1918
  }
2016
1919
  render(stack, rx) {
2017
1920
  const childNodes = new Array(this.childs.length);
2018
- for (let i = 0; i < childNodes.length; i++)
2019
- childNodes[i] = this.childs[i]?.render?.(stack, rx) ?? null;
1921
+ for (let i = 0; i < childNodes.length; i++) childNodes[i] = this.childs[i].render(stack, rx);
2020
1922
  return rx.renderTag(this.tagName, this.attrs.eval(stack), childNodes, this.namespace);
2021
1923
  }
2022
1924
  setDataAttr(key, val) {
@@ -2028,7 +1930,7 @@ var DomNode = class extends ChildsNode {
2028
1930
  };
2029
1931
  var FragmentNode = class extends ChildsNode {
2030
1932
  render(stack, rx) {
2031
- return rx.renderFragment(this.childs.map((c) => c?.render(stack, rx)));
1933
+ return rx.renderFragment(this.childs.map((c) => c.render(stack, rx)));
2032
1934
  }
2033
1935
  setDataAttr(key, val) {
2034
1936
  for (const child of this.childs) child.setDataAttr(key, val);
@@ -2042,8 +1944,10 @@ var ANode = class _ANode extends BaseNode {
2042
1944
  this.nodeId = nodeId;
2043
1945
  this.val = val;
2044
1946
  }
2045
- toPathStep(ctx) {
2046
- return ctx.applyKey(this.val?.toPathItem?.() ?? null);
1947
+ // The addressing step this node contributes to an event's dispatch path, given
1948
+ // the `StepCtx` of the meta that named it; null when it addresses nothing.
1949
+ toPathStep(_ctx) {
1950
+ return this.val?.toPathItem?.() ?? null;
2047
1951
  }
2048
1952
  static parse(html2, px) {
2049
1953
  const nodes = px.parseHTML(html2);
@@ -2059,8 +1963,8 @@ var ANode = class _ANode extends BaseNode {
2059
1963
  return maybeFragment(trimmed);
2060
1964
  }
2061
1965
  static fromDOM(node, px) {
2062
- if (node instanceof px.Text) return new TextNode(node.textContent);
2063
- else if (node instanceof px.Comment) return new CommentNode(node.textContent);
1966
+ if (node.nodeType === 3) return new TextNode(node.textContent);
1967
+ if (node.nodeType === 8) return new CommentNode(node.textContent);
2064
1968
  const { childNodes, attributes: attrs, tagName: tag } = node;
2065
1969
  const childs = [];
2066
1970
  for (let i = 0; i < childNodes.length; i++) {
@@ -2078,11 +1982,11 @@ var ANode = class _ANode extends BaseNode {
2078
1982
  const slotName = attrs.getNamedItem("name")?.value ?? "_";
2079
1983
  return px.frame.macroSlots[slotName] ?? maybeFragment(childs);
2080
1984
  }
2081
- const [nAttrs, wrappers] = Attributes.parse(attrs, px, true);
1985
+ const [nAttrs, wrappers] = new AttrParser(px).parse(attrs, true);
2082
1986
  px.onAttributes(nAttrs, wrappers, null, true, tag);
2083
1987
  return wrap(px.newMacroNode(macroName, nAttrs.toMacroVars(), childs), px, wrappers);
2084
1988
  } else if (VALID_NODE_RE.test(tag)) {
2085
- const [nAttrs, wrappers, textChild] = Attributes.parse(attrs, px);
1989
+ const [nAttrs, wrappers, textChild] = new AttrParser(px).parse(attrs);
2086
1990
  px.onAttributes(nAttrs, wrappers, textChild, false, tag);
2087
1991
  if (textChild) childs.unshift(new RenderTextNode(null, textChild));
2088
1992
  const domChilds = tag !== "PRE" ? condenseChildsWhites(childs) : childs;
@@ -2244,17 +2148,12 @@ var RenderViewId = class extends ANode {
2244
2148
  evalViewName(stack) {
2245
2149
  return this.viewVal ? this.viewVal.eval(stack) : null;
2246
2150
  }
2247
- // A `<x render*>` produces no DOM element of its own to carry `data-cid`;
2248
- // when it is a view's root the component boundary is recorded in the `Comp`
2249
- // meta comment instead (see Renderer._rValComp), so this is a no-op.
2250
- setDataAttr(_key, _val) {
2251
- }
2252
2151
  };
2253
2152
  var RenderNode = class extends RenderViewId {
2254
2153
  render(stack, rx) {
2255
2154
  const [value, renderPath, base] = renderTarget(this.val, stack);
2256
2155
  const newStack = stack.enter(value, {}, true, renderPath, false);
2257
- return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
2156
+ return rx.renderIt(newStack, this, this.evalViewName(stack), base);
2258
2157
  }
2259
2158
  // A `*name` target contributes no step: the site recorded the absolute base it
2260
2159
  // resumed at, and event reconstruction turns that into a continuation frame.
@@ -2267,7 +2166,7 @@ var RenderItNode = class extends RenderViewId {
2267
2166
  render(stack, rx) {
2268
2167
  const base = stack.pendingFrame ? stack.renderPath.toTransactionPath() : null;
2269
2168
  const newStack = stack.enter(stack.it, {}, true, stack.renderPath, false);
2270
- return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
2169
+ return rx.renderIt(newStack, this, this.evalViewName(stack), base);
2271
2170
  }
2272
2171
  toPathStep(ctx) {
2273
2172
  const next = ctx.next();
@@ -2296,9 +2195,6 @@ var RenderTextNode = class extends ANode {
2296
2195
  render(stack, _rx) {
2297
2196
  return this.val.eval(stack);
2298
2197
  }
2299
- // Renders to a text node, which can't carry `data-cid`.
2300
- setDataAttr(_key, _val) {
2301
- }
2302
2198
  };
2303
2199
  var RenderOnceNode = class extends BaseNode {
2304
2200
  constructor(node) {
@@ -2373,13 +2269,29 @@ var ScopeNode = class extends WrapperNode {
2373
2269
  var EachNode = class extends WrapperNode {
2374
2270
  constructor(nodeId, val) {
2375
2271
  super(nodeId, val);
2376
- this.iterInfo = new IterInfo(val, null, null, null);
2272
+ this.iterInfo = new IterInfo();
2377
2273
  }
2378
2274
  render(stack, rx) {
2379
2275
  return rx.renderEachWhen(stack, this);
2380
2276
  }
2277
+ // The sequence and the three loop handlers, resolved against `stack`.
2278
+ evalIter(stack) {
2279
+ const { whenVal, loopWithVal, enrichWithVal } = this.iterInfo;
2280
+ return {
2281
+ seq: this.val.eval(stack) ?? [],
2282
+ filter: whenVal?.evalAsHandler(stack) ?? filterAlwaysTrue,
2283
+ loopWith: loopWithVal?.evalAsHandler(stack) ?? nullLoopWith,
2284
+ enricher: enrichWithVal?.evalAsHandler(stack) ?? null
2285
+ };
2286
+ }
2287
+ // Rebuild the per-item binds for `key` (see iteration.js bindsForKey).
2288
+ enrichBinds(stack, key) {
2289
+ const { seq, filter, loopWith, enricher } = this.evalIter(stack);
2290
+ const ctx = makeLoopCtx(stack, filter);
2291
+ return bindsForKey({ seq, it: stack.it, loopWith, enricher, ctx }, key);
2292
+ }
2381
2293
  toPathStep(ctx) {
2382
- return ctx.hasKey ? new EachBindStep(this.iterInfo, ctx.key) : null;
2294
+ return ctx.hasKey ? new EachBindStep(this, ctx.key) : null;
2383
2295
  }
2384
2296
  // Where one item lives, for the render path. `@each` re-binds `it` to the item
2385
2297
  // whether or not the body is a component, so the position moves either way and
@@ -2392,24 +2304,10 @@ var EachNode = class extends WrapperNode {
2392
2304
  static register = true;
2393
2305
  };
2394
2306
  var IterInfo = class {
2395
- constructor(val, whenVal, loopWithVal, enrichWithVal) {
2396
- this.val = val;
2397
- this.whenVal = whenVal;
2398
- this.loopWithVal = loopWithVal;
2399
- this.enrichWithVal = enrichWithVal;
2400
- }
2401
- eval(stack) {
2402
- const seq = this.val.eval(stack) ?? [];
2403
- const filter = this.whenVal?.evalAsHandler(stack) ?? filterAlwaysTrue;
2404
- const loopWith = this.loopWithVal?.evalAsHandler(stack) ?? nullLoopWith;
2405
- const enricher = this.enrichWithVal?.evalAsHandler(stack) ?? null;
2406
- return { seq, filter, loopWith, enricher };
2407
- }
2408
- // Rebuild the per-item binds for `key` (see iteration.js bindsForKey).
2409
- enrichBinds(stack, key) {
2410
- const { seq, filter, loopWith, enricher } = this.eval(stack);
2411
- const ctx = makeLoopCtx(stack, filter);
2412
- return bindsForKey({ seq, it: stack.it, loopWith, enricher, ctx }, key);
2307
+ constructor() {
2308
+ this.whenVal = null;
2309
+ this.loopWithVal = null;
2310
+ this.enrichWithVal = null;
2413
2311
  }
2414
2312
  };
2415
2313
  function xOp(consumed = [], { wrappable = false, wrapper = null, ignoresChildren = false } = {}) {
@@ -2437,26 +2335,31 @@ var WRAPPER_NODES = {
2437
2335
  scope: ScopeNode,
2438
2336
  "push-view": PushViewNameNode
2439
2337
  };
2440
- var ParseContext = class _ParseContext {
2441
- constructor(document2, Text, Comment, nodes, events, macroNodes, frame, parent) {
2442
- this.nodes = nodes ?? [];
2443
- this.events = events ?? [];
2444
- this.macroNodes = macroNodes ?? [];
2445
- this.parent = parent ?? null;
2446
- this.frame = frame ?? {};
2447
- this.document = document2 ?? globalThis.document;
2448
- this.Text = Text ?? globalThis.Text;
2449
- this.Comment = Comment ?? globalThis.Comment;
2450
- this.cacheConstNodes = true;
2338
+ var ParseContext = class {
2339
+ constructor(document2 = globalThis.document) {
2340
+ this.document = document2;
2341
+ this.nodes = [];
2342
+ this.events = [];
2343
+ this.macroNodes = [];
2344
+ this.parent = null;
2345
+ this.frame = {};
2451
2346
  this.currentTag = null;
2452
2347
  }
2453
2348
  isInsideMacro(name) {
2454
2349
  return this.frame.macroName === name || this.parent?.isInsideMacro(name);
2455
2350
  }
2351
+ // A macro body parses in a child context that shares every accumulator with
2352
+ // its parent (nodes, events, macroNodes, and whatever a subclass collects) and
2353
+ // differs only in its frame. Cloned rather than constructed so a subclass
2354
+ // keeps collecting inside macro bodies without re-implementing this — the
2355
+ // lint and class-set contexts used to lose (or had to copy) exactly that.
2456
2356
  enterMacro(macroName, macroVars, macroSlots) {
2457
- const { document: document2, Text, Comment, nodes, events, macroNodes } = this;
2458
- const frame = { macroName, macroVars, macroSlots };
2459
- return new _ParseContext(document2, Text, Comment, nodes, events, macroNodes, frame, this);
2357
+ const child = Object.create(Object.getPrototypeOf(this));
2358
+ return Object.assign(child, this, {
2359
+ frame: { macroName, macroVars, macroSlots },
2360
+ parent: this,
2361
+ currentTag: null
2362
+ });
2460
2363
  }
2461
2364
  parseHTML(html2) {
2462
2365
  const t = this.document.createElement("template");
@@ -2521,10 +2424,10 @@ var isBlockDomNode = (n) => {
2521
2424
  return node instanceof DomNode && HTML_BLOCK_TAGS.has(node.tagName);
2522
2425
  };
2523
2426
  var isEmptyText = (c) => c instanceof TextNode && c.val === "";
2524
- var isIgnorableXChild = (c) => c instanceof CommentNode || (c.isWhiteSpace?.() ?? false);
2427
+ var isIgnorableXChild = (c) => c instanceof CommentNode || c.isWhiteSpace();
2525
2428
  var hasMeaningfulChilds = (childs) => childs.some((c) => !isIgnorableXChild(c));
2526
2429
  function trimEdgeWhite(node) {
2527
- if (!node.isWhiteSpace?.()) return false;
2430
+ if (!node.isWhiteSpace()) return false;
2528
2431
  node.condenseWhiteSpace();
2529
2432
  return true;
2530
2433
  }
@@ -2535,7 +2438,7 @@ function condenseChildsWhites(childs) {
2535
2438
  if (last > 0 && trimEdgeWhite(childs[last])) emptied = true;
2536
2439
  for (let i = 1; i < last; i++) {
2537
2440
  const cur = childs[i];
2538
- if (!(cur.isWhiteSpace?.() && cur.hasNewLine())) continue;
2441
+ if (!(cur.isWhiteSpace() && cur.hasNewLine())) continue;
2539
2442
  const bothBlock = isBlockDomNode(childs[i - 1]) && isBlockDomNode(childs[i + 1]);
2540
2443
  cur.condenseWhiteSpace(bothBlock ? "" : " ");
2541
2444
  if (bothBlock) emptied = true;
@@ -2543,12 +2446,12 @@ function condenseChildsWhites(childs) {
2543
2446
  return emptied ? childs.filter((c) => !isEmptyText(c)) : childs;
2544
2447
  }
2545
2448
  var View = class {
2546
- constructor(name, rawView = "No View Defined", style = "", anode = null, ctx = null) {
2449
+ constructor(name, rawView = "No View Defined", style = "") {
2547
2450
  this.name = name;
2548
- this.anode = anode;
2549
- this.style = style;
2550
- this.ctx = ctx;
2551
2451
  this.rawView = rawView;
2452
+ this.style = style;
2453
+ this.anode = null;
2454
+ this.ctx = null;
2552
2455
  }
2553
2456
  compile(ctx, scope, cid) {
2554
2457
  this.ctx = ctx;
@@ -2556,7 +2459,7 @@ var View = class {
2556
2459
  this.anode.setDataAttr("data-cid", cid);
2557
2460
  this.anode.setDataAttr("data-vid", this.name);
2558
2461
  this.ctx.compile(scope);
2559
- if (ctx.cacheConstNodes) this.anode = optimizeNode(this.anode);
2462
+ this.anode = optimizeNode(this.anode);
2560
2463
  }
2561
2464
  render(stack, rx) {
2562
2465
  if (this.anode === null) {
@@ -2581,7 +2484,7 @@ var NodeEvents = class {
2581
2484
  getHandlersFor(eventName) {
2582
2485
  let r = null;
2583
2486
  for (const handler of this.handlers)
2584
- if (handler.handlesEventName(eventName)) {
2487
+ if (handler.name === eventName) {
2585
2488
  r ??= [];
2586
2489
  r.push(handler);
2587
2490
  }
@@ -2595,9 +2498,6 @@ var NodeEvent = class {
2595
2498
  this.modifierWrapper = compileModifiers(name, modifiers);
2596
2499
  this.modifiers = modifiers;
2597
2500
  }
2598
- handlesEventName(name) {
2599
- return this.name === name;
2600
- }
2601
2501
  getHandlerAndArgs(stack, event) {
2602
2502
  const r = this.handlerCall.getHandlerAndArgs(stack, event);
2603
2503
  r[0] = this.modifierWrapper(r[0], event);
@@ -2649,103 +2549,10 @@ function compileModifiers(eventName, names) {
2649
2549
  };
2650
2550
  }
2651
2551
 
2652
- // src/util/parsectx.js
2653
- var ParseCtxClassSetCollector = class _ParseCtxClassSetCollector extends ParseContext {
2654
- constructor(...args) {
2655
- super(...args);
2656
- this.classes = /* @__PURE__ */ new Set();
2657
- }
2658
- _addClasses(s) {
2659
- for (const v of s.split(/\s+/)) {
2660
- this.classes.add(v);
2661
- }
2662
- }
2663
- enterMacro(macroName, macroVars, macroSlots) {
2664
- const { document: document2, Text, Comment, nodes, events, macroNodes } = this;
2665
- const frame = { macroName, macroVars, macroSlots };
2666
- const v = new _ParseCtxClassSetCollector(
2667
- document2,
2668
- Text,
2669
- Comment,
2670
- nodes,
2671
- events,
2672
- macroNodes,
2673
- frame,
2674
- this
2675
- );
2676
- v.classes = this.classes;
2677
- return v;
2678
- }
2679
- onAttributes(attrs, _wrapperAttrs, _textChild, _isMacroCall, _tag) {
2680
- if (Array.isArray(attrs.items)) {
2681
- for (const attr of attrs.items) {
2682
- if (attr.name !== "class") {
2683
- continue;
2684
- }
2685
- const { val, thenVal, elseVal } = attr;
2686
- if (thenVal !== void 0) {
2687
- this._maybeAddVal(thenVal);
2688
- this._maybeAddVal(elseVal);
2689
- } else {
2690
- this._maybeAddVal(val);
2691
- }
2692
- }
2693
- } else {
2694
- const attr = attrs.items.class;
2695
- if (attr) {
2696
- this._addClasses(attr);
2697
- }
2698
- }
2699
- }
2700
- _maybeAddVal(value) {
2701
- if (!this._maybeAddStrTpl(value) && typeof value?.val === "string") {
2702
- this._addClasses(value.val);
2703
- }
2704
- }
2705
- _maybeAddStrTpl(value) {
2706
- if (value?.vals !== void 0) {
2707
- for (const val of value.vals) {
2708
- if (val instanceof ConstVal && val.val !== "") {
2709
- this._addClasses(val.val);
2710
- }
2711
- }
2712
- return true;
2713
- }
2714
- return false;
2715
- }
2716
- };
2717
- function collectAppClassesInSet(app) {
2718
- const classes = /* @__PURE__ */ new Set();
2719
- for (const Comp of app.comps.byId.values()) {
2720
- for (const key in Comp.views) {
2721
- const view = Comp.views[key];
2722
- for (const name of view.ctx.classes) {
2723
- classes.add(name);
2724
- }
2725
- }
2726
- }
2727
- return classes;
2728
- }
2729
-
2730
2552
  // src/stack.js
2731
2553
  var STOP = /* @__PURE__ */ Symbol("STOP");
2732
2554
  var NEXT = /* @__PURE__ */ Symbol("NEXT");
2733
2555
  var DEFAULT_ROUTE = ["dyn", "lex"];
2734
- function routeLookup(route, lex, dyn) {
2735
- for (let i = 0; i < route.length; i++) {
2736
- const leg = route[i];
2737
- if (leg === "dyn") {
2738
- const v = dyn();
2739
- if (v != null) return v;
2740
- } else if (leg === "lex") {
2741
- const v = lex();
2742
- if (v != null) return v;
2743
- } else {
2744
- console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
2745
- }
2746
- }
2747
- return null;
2748
- }
2749
2556
  var isTypeName = (s) => {
2750
2557
  const c = s.charCodeAt(0);
2751
2558
  return c >= 65 && c <= 90;
@@ -2811,9 +2618,9 @@ var Stack = class _Stack {
2811
2618
  let has = false;
2812
2619
  const base = this._publishBase();
2813
2620
  for (const k in provide) {
2814
- const step = provide[k].val.toPathItem?.() ?? null;
2621
+ const step = provide[k].toPathItem?.() ?? null;
2815
2622
  if (step === null) continue;
2816
- const value = provide[k].val.eval(this);
2623
+ const value = provide[k].eval(this);
2817
2624
  binds[k] = { value, path: base === null ? null : base.concat([step]) };
2818
2625
  has = true;
2819
2626
  }
@@ -2893,7 +2700,7 @@ var Stack = class _Stack {
2893
2700
  const value2 = path2.lookup(this.root, NOT_FOUND);
2894
2701
  if (value2 !== NOT_FOUND) return { value: value2, path: path2 };
2895
2702
  }
2896
- const dval = comp.lookup[name]?.val ?? null;
2703
+ const dval = comp.lookup[name] ?? null;
2897
2704
  if (dval === null) return null;
2898
2705
  const step = dval.toPathItem?.() ?? null;
2899
2706
  const value = dval.eval(this);
@@ -2914,9 +2721,10 @@ var Stack = class _Stack {
2914
2721
  return fn instanceof Function ? fn.call(this.it) : null;
2915
2722
  }
2916
2723
  // The dispatched DOM event / drag info, read only by EventMemberVal's
2917
- // `e.<member>` handler args. Null outside a live event transaction.
2724
+ // `e.<member>` handler args. Null outside a live event transaction (`ctx` is
2725
+ // then a send/intent transaction, which carries no `e`).
2918
2726
  lookupEvent() {
2919
- return this.ctx?.event ?? null;
2727
+ return this.ctx?.e ?? null;
2920
2728
  }
2921
2729
  lookupDragInfo() {
2922
2730
  return this.ctx?.dragInfo ?? null;
@@ -2943,7 +2751,7 @@ var Components = class {
2943
2751
  this.byId = /* @__PURE__ */ new Map();
2944
2752
  }
2945
2753
  registerComponent(Comp) {
2946
- this.byId.set(Comp[COMPONENT].id, Comp);
2754
+ this.byId.set(Comp.id, Comp);
2947
2755
  }
2948
2756
  getComponentForId(id) {
2949
2757
  return this.byId.get(id) ?? null;
@@ -2963,7 +2771,7 @@ var Components = class {
2963
2771
  }
2964
2772
  compileStyles() {
2965
2773
  const styles = [];
2966
- for (const Comp of this.byId.values()) styles.push(Comp[COMPONENT].compileStyle());
2774
+ for (const Comp of this.byId.values()) styles.push(Comp.compileStyle());
2967
2775
  return styles.join("\n");
2968
2776
  }
2969
2777
  };
@@ -2984,7 +2792,7 @@ var ComponentStack = class _ComponentStack {
2984
2792
  if (paths) this.registerPaths(paths);
2985
2793
  for (let i = 0; i < comps.length; i++) {
2986
2794
  const Comp = comps[i];
2987
- Comp[COMPONENT].scope = this.enter();
2795
+ Comp.scope = this.enter();
2988
2796
  this.comps.registerComponent(Comp);
2989
2797
  this.byName[Comp.name] = Comp;
2990
2798
  }
@@ -3010,7 +2818,7 @@ var ComponentStack = class _ComponentStack {
3010
2818
  console.warn("registerPaths: a type name has no path", name);
3011
2819
  continue;
3012
2820
  }
3013
- this.paths[name] = paths[name].toPath?.() ?? paths[name];
2821
+ this.paths[name] = paths[name].toPath();
3014
2822
  }
3015
2823
  }
3016
2824
  lookupPath(name) {
@@ -3062,77 +2870,67 @@ var ComponentStack = class _ComponentStack {
3062
2870
  return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
3063
2871
  }
3064
2872
  };
3065
- var ProvideInfo = class {
3066
- constructor(val) {
3067
- this.val = val;
3068
- }
3069
- };
3070
- var LookupInfo = class {
3071
- constructor(val) {
3072
- this.val = val;
3073
- }
3074
- };
3075
2873
  var isString = (v) => typeof v === "string";
3076
2874
  var _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
3077
2875
  var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
3078
2876
  var _compId = 0;
3079
- var Component = class {
3080
- constructor(Class, o) {
3081
- this.id = _compId++;
3082
- this.name = o.name ?? "UnkComp";
3083
- this.Class = Class;
3084
- this.views = { main: new View("main", o.view, o.style) };
3085
- this.commonStyle = o.commonStyle ?? "";
3086
- this.globalStyle = o.globalStyle ?? "";
3087
- this.receive = o.receive ?? {};
3088
- this.intent = o.intent ?? {};
3089
- this.alter = o.alter ?? {};
3090
- for (const name in o.views ?? {}) {
3091
- const v = o.views[name];
3092
- const { view, style } = isString(v) ? { view: v } : v;
3093
- this.views[name] = new View(name, view, style);
3094
- }
3095
- this._rawProvide = o.provide ?? {};
3096
- this._rawLookup = o.lookup ?? [];
3097
- this.provide = {};
3098
- this.provideType = {};
3099
- this.lookup = {};
3100
- this.scope = null;
3101
- this.spec = o;
3102
- this.extra = {};
3103
- for (const key of Object.keys(o)) if (!KNOWN_SPEC_KEYS.has(key)) this.extra[key] = o[key];
3104
- }
2877
+ function initComponent(Class, o) {
2878
+ Class[COMPONENT] = Class;
2879
+ Class.id = _compId++;
2880
+ Class.views = { main: new View("main", o.view, o.style) };
2881
+ Class.commonStyle = o.commonStyle ?? "";
2882
+ Class.globalStyle = o.globalStyle ?? "";
2883
+ Class.receive = o.receive ?? {};
2884
+ Class.intent = o.intent ?? {};
2885
+ Class.alter = o.alter ?? {};
2886
+ for (const name in o.views ?? {}) {
2887
+ const v = o.views[name];
2888
+ const { view, style } = isString(v) ? { view: v } : v;
2889
+ Class.views[name] = new View(name, view, style);
2890
+ }
2891
+ Class._rawProvide = o.provide ?? {};
2892
+ Class._rawLookup = o.lookup ?? [];
2893
+ Class.provide = {};
2894
+ Class.provideType = {};
2895
+ Class.lookup = {};
2896
+ Class.scope = null;
2897
+ Class.spec = o;
2898
+ Class.extra = {};
2899
+ for (const key of Object.keys(o)) if (!KNOWN_SPEC_KEYS.has(key)) Class.extra[key] = o[key];
2900
+ return Object.assign(Class, COMPONENT_METHODS);
2901
+ }
2902
+ var COMPONENT_METHODS = {
3105
2903
  compile(ParseContext2) {
3106
2904
  for (const name in this.views)
3107
2905
  this.views[name].compile(new ParseContext2(), this.scope, this.id);
3108
2906
  const ctx = this.views.main.ctx;
3109
2907
  for (const key in this._rawProvide) {
3110
2908
  if (isTypeName(key)) {
3111
- if (this._rawProvide[key] === "self") this.provideType[key] = this.Class;
2909
+ if (this._rawProvide[key] === "self") this.provideType[key] = this;
3112
2910
  continue;
3113
2911
  }
3114
2912
  const val = parseProvide(this._rawProvide[key], ctx);
3115
- if (val) this.provide[key] = new ProvideInfo(val);
2913
+ if (val) this.provide[key] = val;
3116
2914
  }
3117
2915
  for (const entry of this._rawLookup) {
3118
2916
  const name = isString(entry) ? entry : isString(entry?.name) ? entry.name : null;
3119
2917
  if (name === null) continue;
3120
2918
  const defStr = isString(entry?.default) ? entry.default : null;
3121
- this.lookup[name] = new LookupInfo(defStr === null ? null : parseField(defStr, ctx));
2919
+ this.lookup[name] = defStr === null ? null : parseField(defStr, ctx);
3122
2920
  }
3123
2921
  for (const key in this.lookup)
3124
2922
  if (this.provide[key] !== void 0)
3125
2923
  console.warn("name declared in both provide and lookup", this.name, key);
3126
- }
2924
+ },
3127
2925
  getView(name) {
3128
2926
  return this.views[name] ?? this.views.main;
3129
- }
3130
- getEventForId(id, name = "main") {
3131
- return this.getView(name).ctx.getEventForId(id);
3132
- }
3133
- getNodeForId(id, name = "main") {
3134
- return this.getView(name).ctx.getNodeForId(id);
3135
- }
2927
+ },
2928
+ getEventForId(id, viewName) {
2929
+ return this.getView(viewName).ctx.getEventForId(id);
2930
+ },
2931
+ getNodeForId(id, viewName) {
2932
+ return this.getView(viewName).ctx.getNodeForId(id);
2933
+ },
3136
2934
  compileStyle() {
3137
2935
  const { id, commonStyle, globalStyle, views } = this;
3138
2936
  const styles = commonStyle ? [`[data-cid="${id}"]{${commonStyle}}`] : [];
@@ -3145,6 +2943,68 @@ var Component = class {
3145
2943
  }
3146
2944
  };
3147
2945
 
2946
+ // src/util/parsectx.js
2947
+ var ParseCtxClassSetCollector = class extends ParseContext {
2948
+ constructor(...args) {
2949
+ super(...args);
2950
+ this.classes = /* @__PURE__ */ new Set();
2951
+ }
2952
+ _addClasses(s) {
2953
+ for (const v of s.split(/\s+/)) {
2954
+ this.classes.add(v);
2955
+ }
2956
+ }
2957
+ onAttributes(attrs, _wrapperAttrs, _textChild, _isMacroCall, _tag) {
2958
+ if (Array.isArray(attrs.items)) {
2959
+ for (const attr of attrs.items) {
2960
+ if (attr.name !== "class") {
2961
+ continue;
2962
+ }
2963
+ const { val, thenVal, elseVal } = attr;
2964
+ if (thenVal !== void 0) {
2965
+ this._maybeAddVal(thenVal);
2966
+ this._maybeAddVal(elseVal);
2967
+ } else {
2968
+ this._maybeAddVal(val);
2969
+ }
2970
+ }
2971
+ } else {
2972
+ const attr = attrs.items.class;
2973
+ if (attr) {
2974
+ this._addClasses(attr);
2975
+ }
2976
+ }
2977
+ }
2978
+ _maybeAddVal(value) {
2979
+ if (!this._maybeAddStrTpl(value) && typeof value?.val === "string") {
2980
+ this._addClasses(value.val);
2981
+ }
2982
+ }
2983
+ _maybeAddStrTpl(value) {
2984
+ if (value?.vals !== void 0) {
2985
+ for (const val of value.vals) {
2986
+ if (val instanceof ConstVal && val.val !== "") {
2987
+ this._addClasses(val.val);
2988
+ }
2989
+ }
2990
+ return true;
2991
+ }
2992
+ return false;
2993
+ }
2994
+ };
2995
+ function collectAppClassesInSet(app) {
2996
+ const classes = /* @__PURE__ */ new Set();
2997
+ for (const Comp of app.comps.byId.values()) {
2998
+ for (const key in Comp.views) {
2999
+ const view = Comp.views[key];
3000
+ for (const name of view.ctx.classes) {
3001
+ classes.add(name);
3002
+ }
3003
+ }
3004
+ }
3005
+ return classes;
3006
+ }
3007
+
3148
3008
  // tools/core/html-tokenizer.js
3149
3009
  var CharCodes = {
3150
3010
  Tab: 9,
@@ -5452,6 +5312,7 @@ var IF_NO_BRANCH_SET = "IF_NO_BRANCH_SET";
5452
5312
  var UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME";
5453
5313
  var UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG";
5454
5314
  var UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE";
5315
+ var ORPHAN_DIRECTIVE = "ORPHAN_DIRECTIVE";
5455
5316
  var UNKNOWN_X_OP = "UNKNOWN_X_OP";
5456
5317
  var UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR";
5457
5318
  var X_OP_IGNORES_CHILDREN = "X_OP_IGNORES_CHILDREN";
@@ -5486,6 +5347,7 @@ var LEVEL_ERROR2 = "error";
5486
5347
  var LEVEL_HINT = "hint";
5487
5348
  var PARSE_ISSUES = {
5488
5349
  "unknown-directive": { id: UNKNOWN_DIRECTIVE, candidates: KNOWN_DIRECTIVE_NAMES },
5350
+ "orphan-directive": { id: ORPHAN_DIRECTIVE },
5489
5351
  "unknown-x-op": { id: UNKNOWN_X_OP, candidates: X_KNOWN_OP_NAMES, atPrefix: X_KNOWN_OP_NAMES },
5490
5352
  "unknown-x-attr": {
5491
5353
  id: UNKNOWN_X_ATTR,
@@ -6283,7 +6145,7 @@ function checkLookupsHaveProviders(lx, Comp) {
6283
6145
  for (const name in Comp.lookup) {
6284
6146
  if (isTypeName2(name)) continue;
6285
6147
  if (scope.hasProvider?.(name) || scope.lookupPath?.(name)) continue;
6286
- const info = { name, hasDefault: Comp.lookup[name].val != null };
6148
+ const info = { name, hasDefault: Comp.lookup[name] != null };
6287
6149
  if (info.hasDefault) lx.hint(LOOKUP_NO_PROVIDER, info);
6288
6150
  else lx.error(LOOKUP_NO_PROVIDER, info);
6289
6151
  }
@@ -6331,13 +6193,14 @@ var LintContext = class {
6331
6193
  this.reports.push({ id, info, level, context: { ...this.frame }, suggestion });
6332
6194
  }
6333
6195
  };
6334
- var LintParseContext = class extends ParseContext {
6335
- constructor(document2, Text, Comment) {
6336
- super(document2, Text, Comment);
6196
+ var LintParseContext = class extends ParseCtxClassSetCollector {
6197
+ constructor(document2) {
6198
+ super(document2);
6337
6199
  this.attrs = [];
6338
6200
  this.parseIssues = [];
6339
6201
  }
6340
6202
  onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false, tag = null) {
6203
+ super.onAttributes(attrs, wrapperAttrs, textChild, isMacroCall, tag);
6341
6204
  this.attrs.push({ attrs, wrapperAttrs, textChild, isMacroCall, tag });
6342
6205
  }
6343
6206
  onParseIssue(kind, info) {
@@ -6374,14 +6237,36 @@ function dispatchPhase(dispatcher, targetPath, phase, self) {
6374
6237
 
6375
6238
  // src/oo.js
6376
6239
  var BAD_VALUE2 = /* @__PURE__ */ Symbol("BadValue");
6377
- var nullCoercer = (v) => v;
6240
+ var COERCE_NONE = (_v) => null;
6241
+ var COERCE_MAP = (v) => {
6242
+ if (v instanceof Map) return new Map(v);
6243
+ if (Array.isArray(v) || isPlainObject(v))
6244
+ return new Map(Array.isArray(v) ? v : Object.entries(v));
6245
+ return null;
6246
+ };
6247
+ var FIELD_TYPES = {
6248
+ any: [(_v) => true, COERCE_NONE, () => null],
6249
+ text: [(v) => typeof v === "string", (v) => v?.toString?.() ?? "", () => ""],
6250
+ int: [Number.isInteger, (v) => Number.isFinite(v) ? Math.trunc(v) : null, () => 0],
6251
+ float: [Number.isFinite, COERCE_NONE, () => 0],
6252
+ bool: [(v) => typeof v === "boolean", (v) => !!v, () => false],
6253
+ list: [Array.isArray, (v) => Array.isArray(v) ? [...v] : null, () => []],
6254
+ object: [isPlainObject, (v) => isPlainObject(v) ? { ...v } : null, () => ({})],
6255
+ map: [(v) => v instanceof Map, COERCE_MAP, () => /* @__PURE__ */ new Map()],
6256
+ set: [
6257
+ (v) => v instanceof Set,
6258
+ (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null,
6259
+ () => /* @__PURE__ */ new Set()
6260
+ ]
6261
+ };
6378
6262
  var Field = class {
6379
- constructor(type, name, typeCheck, coercer, defaultValue = null) {
6263
+ // `type` names an entry of FIELD_TYPES; `defaultValue` falls back to the type's own.
6264
+ constructor(type, name, defaultValue, [typeCheck, coercer, makeDefault] = FIELD_TYPES[type]) {
6380
6265
  this.type = type;
6381
6266
  this.name = name;
6382
6267
  this.typeCheck = typeCheck;
6383
6268
  this.coercer = coercer;
6384
- this.defaultValue = defaultValue;
6269
+ this.defaultValue = defaultValue === void 0 ? makeDefault() : defaultValue;
6385
6270
  }
6386
6271
  isValid(v) {
6387
6272
  return this.typeCheck(v);
@@ -6395,81 +6280,14 @@ var Field = class {
6395
6280
  return this.coerceOr(v, this.defaultValue);
6396
6281
  }
6397
6282
  };
6398
- var CHECK_TYPE_ANY = (_v) => true;
6399
- var CHECK_TYPE_INT = Number.isInteger;
6400
- var CHECK_TYPE_FLOAT = Number.isFinite;
6401
- var CHECK_TYPE_BOOL = (v) => typeof v === "boolean";
6402
- var CHECK_TYPE_STRING = (v) => typeof v === "string";
6403
- var CHECK_TYPE_LIST = Array.isArray;
6404
- var CHECK_TYPE_OBJECT = isPlainObject;
6405
- var CHECK_TYPE_MAP = (v) => v instanceof Map;
6406
- var CHECK_TYPE_SET = (v) => v instanceof Set;
6407
- var COERCE_NONE = (_v) => null;
6408
- var COERCE_BOOL = (v) => !!v;
6409
- var COERCE_STRING = (v) => v?.toString?.() ?? "";
6410
- var COERCE_INT = (v) => Number.isFinite(v) ? Math.trunc(v) : null;
6411
- var COERCE_LIST = (v) => Array.isArray(v) ? [...v] : null;
6412
- var COERCE_OBJECT = (v) => isPlainObject(v) ? { ...v } : null;
6413
- var COERCE_MAP = (v) => {
6414
- if (v instanceof Map) return new Map(v);
6415
- if (Array.isArray(v) || isPlainObject(v))
6416
- return new Map(Array.isArray(v) ? v : Object.entries(v));
6417
- return null;
6418
- };
6419
- var COERCE_SET = (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null;
6420
- var FieldBool = class extends Field {
6421
- constructor(name, defaultValue = false) {
6422
- super("bool", name, CHECK_TYPE_BOOL, COERCE_BOOL, defaultValue);
6423
- }
6424
- };
6425
- var FieldAny = class extends Field {
6426
- constructor(name, defaultValue = null) {
6427
- super("any", name, CHECK_TYPE_ANY, nullCoercer, defaultValue);
6428
- }
6429
- };
6430
- var FieldString = class extends Field {
6431
- constructor(name, defaultValue = "") {
6432
- super("text", name, CHECK_TYPE_STRING, COERCE_STRING, defaultValue);
6433
- }
6434
- };
6435
- var FieldInt = class extends Field {
6436
- constructor(name, defaultValue = 0) {
6437
- super("int", name, CHECK_TYPE_INT, COERCE_INT, defaultValue);
6438
- }
6439
- };
6440
- var FieldFloat = class extends Field {
6441
- constructor(name, defaultValue = 0) {
6442
- super("float", name, CHECK_TYPE_FLOAT, COERCE_NONE, defaultValue);
6443
- }
6444
- };
6445
- var metaOf = (v) => v?.constructor?.[COMPONENT] ?? v?.constructor?.getMetaClass?.();
6283
+ var metaOf = (v) => v?.constructor?.getMetaClass?.();
6446
6284
  var getTypeName = (v) => metaOf(v)?.name ?? null;
6447
6285
  var FieldComp = class extends Field {
6448
6286
  constructor(type, name, args) {
6449
- super(type, name, (v) => getTypeName(v) === type, nullCoercer, null);
6287
+ super(type, name, null, [(v) => getTypeName(v) === type, COERCE_NONE, () => null]);
6450
6288
  this.args = args;
6451
6289
  }
6452
6290
  };
6453
- var FieldList = class extends Field {
6454
- constructor(name, defaultValue = []) {
6455
- super("list", name, CHECK_TYPE_LIST, COERCE_LIST, defaultValue);
6456
- }
6457
- };
6458
- var FieldObject = class extends Field {
6459
- constructor(name, defaultValue = {}) {
6460
- super("object", name, CHECK_TYPE_OBJECT, COERCE_OBJECT, defaultValue);
6461
- }
6462
- };
6463
- var FieldMap = class extends Field {
6464
- constructor(name, defaultValue = /* @__PURE__ */ new Map()) {
6465
- super("map", name, CHECK_TYPE_MAP, COERCE_MAP, defaultValue);
6466
- }
6467
- };
6468
- var FieldSet = class extends Field {
6469
- constructor(name, defaultValue = /* @__PURE__ */ new Set()) {
6470
- super("set", name, CHECK_TYPE_SET, COERCE_SET, defaultValue);
6471
- }
6472
- };
6473
6291
  function mkCompField(field, scope, args) {
6474
6292
  const Comp = scope?.lookupComponent(field.type) ?? null;
6475
6293
  if (Comp === null)
@@ -6478,112 +6296,66 @@ function mkCompField(field, scope, args) {
6478
6296
  );
6479
6297
  return Comp?.make({ ...field.args, ...args }, { scope }) ?? null;
6480
6298
  }
6481
- var ClassBuilder = class {
6482
- constructor(name) {
6483
- this.name = name;
6484
- this.fields = {};
6485
- this.compFields = /* @__PURE__ */ new Set();
6486
- this._methods = {};
6487
- this._statics = {};
6488
- }
6489
- build() {
6490
- const { name, fields, compFields, _methods } = this;
6491
- const defaults = Object.fromEntries(
6492
- Object.entries(fields).map(([fieldName, field]) => [fieldName, field.defaultValue])
6493
- );
6494
- const Class = {
6495
- [name]: class {
6496
- constructor(values = {}) {
6497
- Object.assign(this, defaults, values);
6498
- }
6299
+ function fieldFromSpec(name, value) {
6300
+ const type = typeof value;
6301
+ if (type === "string") return new Field("text", name, value);
6302
+ if (type === "number") return new Field("float", name, value);
6303
+ if (type === "boolean") return new Field("bool", name, value);
6304
+ if (Array.isArray(value)) return new Field("list", name, [...value]);
6305
+ if (value instanceof Set) return new Field("set", name, new Set(value));
6306
+ if (value instanceof Map) return new Field("map", name, new Map(value));
6307
+ if (value?.type && Object.hasOwn(value, "defaultValue")) {
6308
+ const t = value.type in FIELD_TYPES ? value.type : "any";
6309
+ const probe = new Field(t, name);
6310
+ return new Field(t, name, probe.coerceOr(value.defaultValue, probe.defaultValue));
6311
+ }
6312
+ if (value?.component && value?.args !== void 0)
6313
+ return new FieldComp(value.component, name, value.args);
6314
+ if (isPlainObject(value)) return new Field("object", name, { ...value });
6315
+ return new Field("any", name, value);
6316
+ }
6317
+ function classFromData(name, { fields: spec = {}, methods = {}, statics = {} }) {
6318
+ const fields = {};
6319
+ for (const key in spec) fields[key] = fieldFromSpec(key, spec[key]);
6320
+ const defaults = Object.fromEntries(
6321
+ Object.entries(fields).map(([key, field]) => [key, field.defaultValue])
6322
+ );
6323
+ const Class = {
6324
+ [name]: class {
6325
+ constructor(values = {}) {
6326
+ Object.assign(this, defaults, values);
6499
6327
  }
6500
- }[name];
6501
- Class[immer_exports.immerable] = true;
6502
- Object.assign(Class.prototype, _methods);
6503
- const metaClass = { fields, name, methods: _methods };
6504
- Object.assign(
6505
- Class,
6506
- {
6507
- getMetaClass: () => metaClass,
6508
- make(inArgs = {}, opts = {}) {
6509
- const args = {};
6510
- const scope = opts.scope ?? this[COMPONENT]?.scope ?? this.scope;
6511
- for (const key in inArgs) {
6512
- const field = fields[key];
6513
- if (compFields.has(key)) args[key] = mkCompField(field, scope, inArgs[key]);
6514
- else if (field === void 0)
6515
- console.warn("extra argument to constructor:", name, key, inArgs);
6516
- else args[key] = field.coerceOrDefault(inArgs[key]);
6517
- }
6518
- for (const key of compFields)
6519
- if (args[key] === void 0) args[key] = mkCompField(fields[key], scope, inArgs[key]);
6520
- return (0, immer_exports.freeze)(new this(args), true);
6521
- }
6522
- },
6523
- this._statics
6524
- );
6525
- return Class;
6526
- }
6527
- methods(proto) {
6528
- for (const k in proto) this._methods[k] = proto[k];
6529
- }
6530
- statics(proto) {
6531
- for (const k in proto) this._statics[k] = proto[k];
6532
- }
6533
- addField(name, dval, FieldCls) {
6534
- const field = new FieldCls(name, dval);
6535
- this.fields[name] = field;
6536
- return field;
6537
- }
6538
- addCompField(name, type, args) {
6539
- const field = new FieldComp(type, name, args);
6540
- this.compFields.add(name);
6541
- this.fields[name] = field;
6542
- return field;
6543
- }
6544
- };
6545
- var FIELD_CLASS = /* @__PURE__ */ Symbol.for("tutuca.fieldClass");
6546
- var fieldsByTypeName = {
6547
- text: FieldString,
6548
- int: FieldInt,
6549
- float: FieldFloat,
6550
- bool: FieldBool,
6551
- list: FieldList,
6552
- object: FieldObject,
6553
- map: FieldMap,
6554
- set: FieldSet,
6555
- any: FieldAny
6556
- };
6557
- function fieldFromDescriptor(name, value) {
6558
- const FieldCls = fieldsByTypeName[value.type] ?? FieldAny;
6559
- const probe = new FieldCls(name);
6560
- return [FieldCls, probe.coerceOr(value.defaultValue, probe.defaultValue)];
6561
- }
6562
- function classFromData(name, { fields = {}, methods, statics }) {
6563
- const b = new ClassBuilder(name);
6564
- for (const field in fields) {
6565
- const value = fields[field];
6566
- const type = typeof value;
6567
- if (type === "string") b.addField(field, value, FieldString);
6568
- else if (type === "number") b.addField(field, value, FieldFloat);
6569
- else if (type === "boolean") b.addField(field, value, FieldBool);
6570
- else if (Array.isArray(value)) b.addField(field, [...value], FieldList);
6571
- else if (value instanceof Set) b.addField(field, new Set(value), FieldSet);
6572
- else if (value instanceof Map) b.addField(field, new Map(value), FieldMap);
6573
- else if (value?.type && Object.hasOwn(value, "defaultValue")) {
6574
- const [FieldCls, dval] = fieldFromDescriptor(field, value);
6575
- b.addField(field, dval, FieldCls);
6576
- } else if (value?.component && value?.args !== void 0)
6577
- b.addCompField(field, value.component, value.args);
6578
- else if (isPlainObject(value)) b.addField(field, { ...value }, FieldObject);
6579
- else {
6580
- const FieldCls = value?.[FIELD_CLASS] ?? FieldAny;
6581
- b.addField(field, value, FieldCls);
6582
6328
  }
6583
- }
6584
- if (methods) b.methods(methods);
6585
- if (statics) b.statics(statics);
6586
- return b.build();
6329
+ }[name];
6330
+ Class[immer_exports.immerable] = true;
6331
+ Object.assign(Class.prototype, methods);
6332
+ Object.assign(
6333
+ Class,
6334
+ {
6335
+ fields,
6336
+ methods,
6337
+ // The documented way for instance code to reach its class's fields
6338
+ // (`this.constructor.getMetaClass().fields.x.defaultValue`).
6339
+ getMetaClass: () => Class,
6340
+ make(inArgs = {}, opts = {}) {
6341
+ const args = {};
6342
+ const scope = opts.scope ?? this.scope;
6343
+ for (const key in inArgs) {
6344
+ const field = fields[key];
6345
+ if (field === void 0)
6346
+ console.warn("extra argument to constructor:", name, key, inArgs);
6347
+ else if (field instanceof FieldComp) args[key] = mkCompField(field, scope, inArgs[key]);
6348
+ else args[key] = field.coerceOrDefault(inArgs[key]);
6349
+ }
6350
+ for (const key in fields)
6351
+ if (fields[key] instanceof FieldComp && args[key] === void 0)
6352
+ args[key] = mkCompField(fields[key], scope, void 0);
6353
+ return (0, immer_exports.freeze)(new this(args), true);
6354
+ }
6355
+ },
6356
+ statics
6357
+ );
6358
+ return Class;
6587
6359
  }
6588
6360
  function validateDraftFields(current, draft) {
6589
6361
  const meta = metaOf(current);
@@ -6599,14 +6371,11 @@ function validateDraftFields(current, draft) {
6599
6371
  }
6600
6372
  }
6601
6373
  }
6602
- var META_KEYS = "name id fields methods views receive intent alter provide provideType lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
6603
- " "
6604
- );
6605
6374
  var RESERVED_COMPONENT_STATICS = /* @__PURE__ */ new Set([
6606
- ...META_KEYS,
6607
- "make",
6608
- "getMetaClass",
6609
- ...Object.getOwnPropertyNames(Component.prototype)
6375
+ ..."name id fields methods views receive intent alter provide provideType lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup make getMetaClass".split(
6376
+ " "
6377
+ ),
6378
+ ...Object.keys(COMPONENT_METHODS)
6610
6379
  ]);
6611
6380
  function assertNoReservedComponentStatics(statics = {}) {
6612
6381
  for (const name in statics) {
@@ -6615,32 +6384,10 @@ function assertNoReservedComponentStatics(statics = {}) {
6615
6384
  }
6616
6385
  }
6617
6386
  }
6618
- Component.fromSpec = (opts) => {
6387
+ function component(opts) {
6619
6388
  assertNoReservedComponentStatics(opts.statics);
6620
- const Class = classFromData(opts.name, opts);
6621
- const comp = new Component(Class, opts);
6622
- const metaClass = Class.getMetaClass();
6623
- comp.fields = metaClass.fields;
6624
- comp.methods = metaClass.methods;
6625
- Class.getMetaClass = () => comp;
6626
- Class[COMPONENT] = comp;
6627
- for (const key of META_KEYS)
6628
- if (!Object.hasOwn(Class, key))
6629
- Object.defineProperty(Class, key, {
6630
- get() {
6631
- return comp[key];
6632
- },
6633
- set(v) {
6634
- comp[key] = v;
6635
- },
6636
- configurable: true
6637
- });
6638
- for (const key of Object.getOwnPropertyNames(Component.prototype))
6639
- if (key !== "constructor" && !Object.hasOwn(Class, key))
6640
- Class[key] = (...args) => comp[key](...args);
6641
- return Class;
6642
- };
6643
- var component = (opts) => Component.fromSpec(opts);
6389
+ return initComponent(classFromData(opts.name ?? "UnkComp", opts), opts);
6390
+ }
6644
6391
 
6645
6392
  // src/transactor.js
6646
6393
  var State2 = class {
@@ -6681,14 +6428,7 @@ var Transactor = class {
6681
6428
  // carry: kind, name, args, path, pathKeys, targetPath, handler, handlerName,
6682
6429
  // matched, before, after, parent, timestamp. Purely observational.
6683
6430
  observe(cb) {
6684
- this._observers.push(cb);
6685
- return () => {
6686
- const i = this._observers.indexOf(cb);
6687
- if (i !== -1) this._observers.splice(i, 1);
6688
- };
6689
- }
6690
- _emit(record) {
6691
- for (const cb of this._observers) cb(record);
6431
+ return subscribe(this._observers, cb);
6692
6432
  }
6693
6433
  // Record a refusal: a dispatch the runtime could not carry out. Kinds are
6694
6434
  // open strings; today the runtime raises NO_HANDLER (a receive name with no
@@ -6707,11 +6447,7 @@ var Transactor = class {
6707
6447
  // Subscribe to refusal records as they happen. Returns an unsubscribe fn,
6708
6448
  // like observe().
6709
6449
  observeRefusals(cb) {
6710
- this._refusalObservers.push(cb);
6711
- return () => {
6712
- const i = this._refusalObservers.indexOf(cb);
6713
- if (i !== -1) this._refusalObservers.splice(i, 1);
6714
- };
6450
+ return subscribe(this._refusalObservers, cb);
6715
6451
  }
6716
6452
  // Build and dispatch one observer record. Pins field-resolved keys (e.g. a
6717
6453
  // `.a[.selId]` render target reconstructed from a DOM event) against the root the
@@ -6720,7 +6456,7 @@ var Transactor = class {
6720
6456
  _emitRecord(root, { kind, name, args, path: path2, targetPath, handler, handlerName, matched, before, after, parent }) {
6721
6457
  if (this._observers.length === 0) return;
6722
6458
  const pinned = path2.pinKeys(root);
6723
- this._emit({
6459
+ const record = {
6724
6460
  kind,
6725
6461
  name,
6726
6462
  args: args ?? null,
@@ -6734,14 +6470,14 @@ var Transactor = class {
6734
6470
  after,
6735
6471
  parent,
6736
6472
  timestamp: Date.now()
6737
- });
6473
+ };
6474
+ for (const cb of this._observers) cb(record);
6738
6475
  }
6739
6476
  // The observer record for a settled transaction. The resolved handler
6740
6477
  // (`_resolvedHandler`/`_matched`) and per-leaf before/after (`_before`/`_after`)
6741
6478
  // were captured while the handler ran (see callHandler / Transaction.run).
6742
6479
  _emitTransaction(transaction, root) {
6743
6480
  if (this._observers.length === 0) return;
6744
- if (transaction._resolvedHandler === void 0) return;
6745
6481
  this._emitRecord(root, {
6746
6482
  kind: transaction.observeKind,
6747
6483
  name: transaction.observeName,
@@ -6755,28 +6491,22 @@ var Transactor = class {
6755
6491
  parent: transaction.parentTransaction
6756
6492
  });
6757
6493
  }
6758
- // Make `child` a tracked unit of `parent`'s subtree: the parent's completion stays open
6759
- // until the child's *whole* subtree settles. Tracking happens at dispatch time — during
6760
- // the parent's handler or afterTransaction — while the parent's self-unit is still held,
6761
- // so the parent counter can't reach zero before the child is registered. Returns `child`.
6762
- _link(child, parent) {
6763
- if (parent) {
6764
- const release = parent.completion.track();
6765
- child.completion.whenSubtreeSettled().then(release);
6766
- }
6767
- return child;
6768
- }
6769
6494
  // `origin` is where the message came FROM, pinned now for the same reason an
6770
6495
  // intent's answerPath is: a reply must reach the sender that asked even if a key
6771
6496
  // moved while the message was in flight. Null when nobody is waiting — a host
6772
6497
  // sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
6498
+ //
6499
+ // The parent's subtree stays open until this message's whole subtree settles. The
6500
+ // unit is taken now, at dispatch — during the parent's handler or afterTransaction,
6501
+ // while the parent's self-unit is still held — so its counter can't reach zero first.
6773
6502
  pushSend(path2, name, args = [], parent = null, origin = null, txnPath = null) {
6774
6503
  const t = new SendEvent(path2, this, name, args, parent);
6775
6504
  t.txnPath = txnPath;
6776
6505
  t.origin = origin;
6777
6506
  t.originPinned = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
6778
6507
  this.pushTransaction(t);
6779
- return this._link(t, parent);
6508
+ if (parent) t.completion.carry(parent.completion.track());
6509
+ return t;
6780
6510
  }
6781
6511
  // Raise an intent: a job the sender did not address, walked along a route until
6782
6512
  // something answers. `opts.route` is a list of legs (see DEFAULT_ROUTE) and
@@ -6800,7 +6530,7 @@ var Transactor = class {
6800
6530
  return this.transactions.length > 0;
6801
6531
  }
6802
6532
  transactNext() {
6803
- if (this.hasPendingTransactions) this.transact(this.transactions.shift());
6533
+ this.transact(this.transactions.shift());
6804
6534
  }
6805
6535
  transact(transaction) {
6806
6536
  try {
@@ -6813,8 +6543,7 @@ var Transactor = class {
6813
6543
  } else console.warn("undefined new state", { curState, transaction });
6814
6544
  } finally {
6815
6545
  transaction.ensureWalkAdvanced?.();
6816
- transaction._completion?.ensureSelfSettled();
6817
- transaction._completion?.releaseSelf();
6546
+ transaction._completion?.finish();
6818
6547
  }
6819
6548
  }
6820
6549
  transactInputNow(path2, event, eventHandler, dragInfo) {
@@ -6824,6 +6553,17 @@ var Transactor = class {
6824
6553
  function nullHandler() {
6825
6554
  return this;
6826
6555
  }
6556
+ function subscribe(list, cb) {
6557
+ list.push(cb);
6558
+ return () => {
6559
+ const i = list.indexOf(cb);
6560
+ if (i !== -1) list.splice(i, 1);
6561
+ };
6562
+ }
6563
+ function warnUnknownLeg(what, leg) {
6564
+ console.warn(`unknown ${what} route leg`, leg, '- expected "dyn" or "lex"');
6565
+ return null;
6566
+ }
6827
6567
  var Transaction = class {
6828
6568
  constructor(path2, transactor, parentTransaction = null) {
6829
6569
  this.path = path2;
@@ -6847,41 +6587,41 @@ var Transaction = class {
6847
6587
  whenSubtreeSettled() {
6848
6588
  return this.completion.whenSubtreeSettled();
6849
6589
  }
6850
- afterTransaction() {
6851
- }
6852
- // Ending a walk and forwarding belong to the two dispatch buckets; the base warns
6853
- // rather than throwing, so a stray call from the wrong place is a message and not a
6854
- // crash. `walk` is undefined here, which is how ctx.reply/ctx.fail tell the two apart.
6855
- stop() {
6856
- warnNotIntent("stop");
6857
- }
6858
- forward(_opts) {
6859
- console.warn('ctx.forward() needs a "receive" or "intent" handler - ignored');
6860
- }
6861
- // The kind reported to observers (see Transactor.observe); null on the base.
6862
- get observeKind() {
6863
- return null;
6864
- }
6865
- // The name reported to observers; null on the base. Overridden by NameArgs (the
6866
- // dispatched message name) and InputEvent (the DOM event type). Kept separate from
6867
- // `name`/`ctx.name` so it can't change handler-visible behavior.
6868
- get observeName() {
6869
- return null;
6870
- }
6590
+ // Every transaction kind defines `observeKind` / `observeName` (what observers see;
6591
+ // kept apart from `name`/`ctx.name` so they can't change handler-visible behavior),
6592
+ // `getHandlerAndArgs(root, instance, comps)`, and the three `_forward*` hooks below.
6871
6593
  callHandler(root, instance, draft, comps) {
6872
6594
  const [handler, args] = this.getHandlerAndArgs(root, instance, comps);
6873
6595
  this._resolvedHandler = handler;
6874
6596
  return handler.apply(instance, [draft, ...args]);
6875
6597
  }
6876
- getHandlerAndArgs(_root, _instance, _comps) {
6877
- return null;
6598
+ // `forward` is where a name can LEAVE the component: the message being handled is
6599
+ // raised again as an INTENT under the same name (`_forwardName()`) with the same
6600
+ // arguments unless `opts.args` says otherwise, from the position `_forwardPath()`
6601
+ // names. Deferred to afterTransaction so the state the handler produced is in place
6602
+ // before the walk starts. (`IntentEvent` overrides both: in an intent body, forward
6603
+ // amends the walk that is already running.)
6604
+ forward(opts) {
6605
+ this._forward = opts ?? {};
6606
+ }
6607
+ afterTransaction() {
6608
+ const f = this._forward;
6609
+ if (f === void 0) return;
6610
+ this._forward = void 0;
6611
+ const name = this._forwardName();
6612
+ if (name === void 0) {
6613
+ this.transactor.refuse("FORWARD_NO_NAME", {});
6614
+ return;
6615
+ }
6616
+ const { args = this._forwardArgs(), ...rest } = f;
6617
+ this.transactor.pushIntent(this._forwardPath(), name, args, rest, this);
6878
6618
  }
6879
6619
  // The path used to apply the mutation: the ACTIVE frame of the dispatch path, so
6880
6620
  // an event inside a `<x render="*name">` subtree updates the value where it
6881
6621
  // really lives (the dispatch `this.path` keeps the visual callers, for bubbling).
6622
+ // `txnPath`, when pinned by the sender, wins.
6882
6623
  getTransactionPath() {
6883
- if (this.txnPath !== null) return this.txnPath;
6884
- return this.path.toTransactionPath().compact();
6624
+ return this.txnPath ?? this.path.toTransactionPath();
6885
6625
  }
6886
6626
  run(curRoot, comps) {
6887
6627
  const txnPath = this.getTransactionPath();
@@ -6912,6 +6652,13 @@ var InputEvent = class extends Transaction {
6912
6652
  this._dispatchPath ??= this.path.compact();
6913
6653
  return this._dispatchPath;
6914
6654
  }
6655
+ // Only a DOM event's path carries frame-only bind steps (they replay the handler's
6656
+ // arguments, but address no state); the compacted path is where the mutation lands,
6657
+ // so a handler inside @each still updates the component that owns the view. Every
6658
+ // other transaction is dispatched at an already-compacted position.
6659
+ getTransactionPath() {
6660
+ return this.dispatchPath.toTransactionPath();
6661
+ }
6915
6662
  // A DOM event is an ADDRESSED message like any other — it reaches the component that
6916
6663
  // owns the view and stops. It keeps its own class only because it resolves its handler
6917
6664
  // from the compiled view and runs synchronously, not because it is a different channel.
@@ -6921,25 +6668,20 @@ var InputEvent = class extends Transaction {
6921
6668
  get observeName() {
6922
6669
  return this.e?.type ?? null;
6923
6670
  }
6924
- // A view's name is a message. `forward` is where that name can LEAVE the component:
6925
- // it becomes an intent with the same name and the same arguments, so a view that says
6926
- // `@on.click="saveDraft .text"` never has to change when an ancestor takes the job over.
6927
- // (A `$method` handler has a name too, so forwarding one raises an intent under it.)
6928
- forward(opts) {
6929
- this._forward = opts ?? {};
6930
- }
6931
- afterTransaction() {
6932
- const f = this._forward;
6933
- if (f === void 0) return;
6934
- this._forward = void 0;
6935
- const { args = this._handlerArgs ?? [], ...rest } = f;
6671
+ // A view's name is a message, and forwarding it means a view that says
6672
+ // `@on.click="saveDraft .text"` never has to change when an ancestor takes the job
6673
+ // over. (A `$method` handler has a name too, so forwarding one raises an intent under
6674
+ // it.) `handler` is a NodeEvent, whose own `name` is the DOM event type; the MESSAGE
6675
+ // name is the one the view wrote, on the handler call it wraps.
6676
+ _forwardName() {
6936
6677
  const hv = this.handler?.handlerCall?.handlerVal ?? this.handler?.handlerVal;
6937
- const name = hv?.name;
6938
- if (name === void 0) {
6939
- this.transactor.refuse("FORWARD_NO_NAME", {});
6940
- return;
6941
- }
6942
- this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
6678
+ return hv?.name;
6679
+ }
6680
+ _forwardArgs() {
6681
+ return this._handlerArgs ?? [];
6682
+ }
6683
+ _forwardPath() {
6684
+ return this.dispatchPath;
6943
6685
  }
6944
6686
  getHandlerAndArgs(root, _instance, comps) {
6945
6687
  const stack = this.path.buildStack(Stack.root(comps, root, this));
@@ -6949,12 +6691,6 @@ var InputEvent = class extends Transaction {
6949
6691
  args.push(new EventContext(path2, this.transactor, this));
6950
6692
  return [handler, args];
6951
6693
  }
6952
- // The dispatched DOM event, read only through `e.<member>` handler args
6953
- // (src/value.js EventMemberVal via Stack.lookupEvent). There is no bare
6954
- // implicit-name vocabulary anymore: every arg carries a sigil.
6955
- get event() {
6956
- return this.e;
6957
- }
6958
6694
  };
6959
6695
  var NameArgsTransaction = class extends Transaction {
6960
6696
  constructor(path2, transactor, name, args, parentTransaction) {
@@ -6972,6 +6708,17 @@ var NameArgsTransaction = class extends Transaction {
6972
6708
  get observeName() {
6973
6709
  return this.name;
6974
6710
  }
6711
+ // `forward` in a RECEIVE body starts a walk: the message that arrived becomes an
6712
+ // intent, keeping its name and payload.
6713
+ _forwardName() {
6714
+ return this.name;
6715
+ }
6716
+ _forwardArgs() {
6717
+ return this.args;
6718
+ }
6719
+ _forwardPath() {
6720
+ return this.path;
6721
+ }
6975
6722
  getHandlerForName(comp) {
6976
6723
  const handlers = comp?.[this.handlerProp];
6977
6724
  const exact = handlers?.[this.name];
@@ -7002,19 +6749,6 @@ var SendEvent = class extends NameArgsTransaction {
7002
6749
  get observeKind() {
7003
6750
  return this._isAnswer ? "answer" : "receive";
7004
6751
  }
7005
- // `forward` in a RECEIVE body starts a walk: the message that arrived becomes an
7006
- // intent, keeping its name and payload. This is what lets a view's name leave the
7007
- // component without the view changing.
7008
- forward(opts) {
7009
- this._forward = opts ?? {};
7010
- }
7011
- afterTransaction() {
7012
- const f = this._forward;
7013
- if (f === void 0) return;
7014
- this._forward = void 0;
7015
- const { args = this.args, ...rest } = f;
7016
- this.transactor.pushIntent(this.path, this.name, args, rest, this);
7017
- }
7018
6752
  };
7019
6753
  var IntentEvent = class extends NameArgsTransaction {
7020
6754
  handlerProp = "intent";
@@ -7028,9 +6762,6 @@ var IntentEvent = class extends NameArgsTransaction {
7028
6762
  forward(opts) {
7029
6763
  this.walk.amend(opts, this.path);
7030
6764
  }
7031
- stop() {
7032
- this.walk.finish(null, null);
7033
- }
7034
6765
  afterTransaction() {
7035
6766
  this.ensureWalkAdvanced();
7036
6767
  }
@@ -7080,7 +6811,7 @@ var IntentWalk = class {
7080
6811
  this.legIndex++;
7081
6812
  return this._tryLex();
7082
6813
  }
7083
- console.warn("unknown intent route leg", leg, '- expected "dyn" or "lex"');
6814
+ warnUnknownLeg("intent", leg);
7084
6815
  this.legIndex++;
7085
6816
  }
7086
6817
  this.exhaust("noHandler");
@@ -7169,7 +6900,7 @@ var IntentWalk = class {
7169
6900
  t.txnPath = this.answerPath;
7170
6901
  t._isAnswer = true;
7171
6902
  this.transactor.pushTransaction(t);
7172
- if (this.release) t.completion.whenSubtreeSettled().then(this.release);
6903
+ if (this.release) t.completion.carry(this.release);
7173
6904
  }
7174
6905
  };
7175
6906
  var Completion = class {
@@ -7177,12 +6908,12 @@ var Completion = class {
7177
6908
  this.val = void 0;
7178
6909
  this.selfSettled = false;
7179
6910
  this.subtreeSettled = false;
7180
- this.pending = 1;
6911
+ this.pending = 0;
7181
6912
  this._selfResolve = null;
7182
6913
  this._selfPromise = null;
7183
6914
  this._subtreeResolve = null;
7184
6915
  this._subtreePromise = null;
7185
- this._selfReleased = false;
6916
+ this._releaseSelf = this.track();
7186
6917
  }
7187
6918
  whenSettled() {
7188
6919
  if (this.selfSettled) return Promise.resolve(this.val);
@@ -7205,38 +6936,38 @@ var Completion = class {
7205
6936
  this.val = val;
7206
6937
  this._selfResolve?.(val);
7207
6938
  }
7208
- // Settle self even when no handler produced a value (undefined-state / throw paths).
7209
- ensureSelfSettled() {
7210
- if (!this.selfSettled) this.markSelfSettled(this.val);
6939
+ // The transaction is done processing: self is settled (with the value the handler
6940
+ // produced, or none on the undefined-state / throw paths) and the self-unit goes.
6941
+ finish() {
6942
+ this.markSelfSettled(this.val);
6943
+ this._releaseSelf();
7211
6944
  }
7212
- // Register an outstanding unit; returns a one-shot release.
6945
+ // Register an outstanding unit; returns its one-shot release. The subtree settles
6946
+ // when the last unit is released.
7213
6947
  track() {
7214
6948
  this.pending++;
7215
6949
  let done = false;
7216
6950
  return () => {
7217
6951
  if (done) return;
7218
6952
  done = true;
7219
- this._release();
6953
+ if (--this.pending === 0) {
6954
+ this.subtreeSettled = true;
6955
+ this._subtreeResolve?.(this.val);
6956
+ }
7220
6957
  };
7221
6958
  }
7222
- releaseSelf() {
7223
- if (this._selfReleased) return;
7224
- this._selfReleased = true;
7225
- this._release();
7226
- }
7227
- _release() {
7228
- if (--this.pending === 0) {
7229
- this.subtreeSettled = true;
7230
- this._subtreeResolve?.(this.val);
7231
- }
6959
+ // Hand a unit held elsewhere to this subtree: `release` runs once this transaction
6960
+ // and everything it spawned have settled.
6961
+ carry(release) {
6962
+ this.whenSubtreeSettled().then(release);
7232
6963
  }
7233
6964
  };
7234
6965
  var Dispatcher = class {
7235
- constructor(path2, transactor, parentTransaction, root = transactor.state.val) {
6966
+ constructor(path2, transactor, parentTransaction) {
7236
6967
  this.path = path2;
7237
6968
  this.transactor = transactor;
7238
6969
  this.parent = parentTransaction;
7239
- this.root = root;
6970
+ this.root = transactor.state.val;
7240
6971
  }
7241
6972
  // Walk the component instances on this ctx's path, leaf→root, calling
7242
6973
  // callback(Component, instance). Return false from the callback to stop early.
@@ -7269,12 +7000,14 @@ var Dispatcher = class {
7269
7000
  // Resolve a name the way the renderer would. `opts.route` takes the same legs in
7270
7001
  // the same spelling as `ctx.intent` — `["dyn"]` the render ancestry, `["lex"]` the
7271
7002
  // registration scope, default both.
7003
+ // Legs are tried in route order, like the intent walker's; an unknown leg warns and
7004
+ // is skipped, and an empty route resolves to null.
7272
7005
  lookup(name, opts) {
7273
- return routeLookup(
7274
- opts?.route ?? DEFAULT_ROUTE,
7275
- () => this._lookupLex(name),
7276
- () => this._stack()?.lookupDynamic(name) ?? null
7277
- );
7006
+ for (const leg of opts?.route ?? DEFAULT_ROUTE) {
7007
+ const v = leg === "dyn" ? this._stack()?.lookupDynamic(name) ?? null : leg === "lex" ? this._lookupLex(name) : warnUnknownLeg("lookup", leg);
7008
+ if (v != null) return v;
7009
+ }
7010
+ return null;
7278
7011
  }
7279
7012
  // The `lex` leg without a Stack: the scope of the component whose handler is
7280
7013
  // running, which is the leaf of this ctx's path. A type name resolves to the
@@ -7359,9 +7092,10 @@ var EventContext = class extends Dispatcher {
7359
7092
  this.parent.originPinned
7360
7093
  );
7361
7094
  }
7362
- // End the walk answering nothing — "served, and no answer".
7095
+ // End the walk answering nothing — "served, and no answer". Like reply/fail,
7096
+ // legal only in an `intent` handler.
7363
7097
  stop() {
7364
- return this.parent.stop();
7098
+ return this.parent.walk === void 0 ? warnNotIntent("stop") : this.parent.walk.finish(null, null);
7365
7099
  }
7366
7100
  // From an `intent` body: hand the intent to the next hop, optionally amending it.
7367
7101
  // From a `receive` body: turn the message that arrived into an intent. One word from
@@ -7944,6 +7678,8 @@ function lintIdToMessage(id, info) {
7944
7678
  return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
7945
7679
  case "UNKNOWN_DIRECTIVE":
7946
7680
  return `Unknown directive '@${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
7681
+ case "ORPHAN_DIRECTIVE":
7682
+ return `'@${info.name}=${JSON.stringify(info.value)}' needs an '@${info.needs}' on the same element — it was ignored${fmtTagSuffix(info)}`;
7947
7683
  case "UNKNOWN_X_OP":
7948
7684
  return `Unknown <x> op '${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
7949
7685
  case "UNKNOWN_X_ATTR":
@@ -8077,7 +7813,6 @@ var App = class {
8077
7813
  this.transactor = new Transactor(comps, null);
8078
7814
  this.ParseContext = ParseContext2;
8079
7815
  this.renderer = renderer;
8080
- this.maxEventNodeDepth = Infinity;
8081
7816
  this._transactNextBatchId = this._evictCacheId = null;
8082
7817
  this._eventNames = new Set(_evs);
8083
7818
  this.dragInfo = this.curDragOver = null;
@@ -8104,12 +7839,11 @@ var App = class {
8104
7839
  _dispatchEvent(e) {
8105
7840
  const { type } = e;
8106
7841
  const isDrag = type === "dragover" || type === "dragstart" || type === "dragend" || type === "drop";
8107
- const { rootNode: root, maxEventNodeDepth: maxDepth, comps, transactor } = this;
7842
+ const { rootNode, comps, transactor } = this;
8108
7843
  const [path2, handlers] = DispatchPath.fromNodeAndEventName(
8109
7844
  e.target,
8110
7845
  type,
8111
- root,
8112
- maxDepth,
7846
+ rootNode,
8113
7847
  comps,
8114
7848
  !isDrag
8115
7849
  );
@@ -8218,10 +7952,9 @@ var App = class {
8218
7952
  }
8219
7953
  compile() {
8220
7954
  for (const Comp of this.comps.byId.values()) {
8221
- const meta = Comp[COMPONENT];
8222
- meta.compile(this.ParseContext);
8223
- for (const key in meta.views)
8224
- for (const name of meta.views[key].ctx.genEventNames()) this._eventNames.add(name);
7955
+ Comp.compile(this.ParseContext);
7956
+ for (const key in Comp.views)
7957
+ for (const name of Comp.views[key].ctx.genEventNames()) this._eventNames.add(name);
8225
7958
  }
8226
7959
  this._compiled = true;
8227
7960
  }
@@ -8244,6 +7977,8 @@ var App = class {
8244
7977
  }
8245
7978
  stop() {
8246
7979
  this.stopCacheEvictionInterval();
7980
+ clearTimeout(this._transactNextBatchId);
7981
+ this._transactNextBatchId = null;
8247
7982
  for (const name of this._eventNames)
8248
7983
  this.rootNode.removeEventListener(name, this, listenerOpts(name));
8249
7984
  }
@@ -8330,28 +8065,21 @@ var NullDomCache = class {
8330
8065
  set(_keys, _cacheKey, _v) {
8331
8066
  }
8332
8067
  evict() {
8333
- return { hit: 0, miss: 0, badKey: 0 };
8334
8068
  }
8335
8069
  };
8336
8070
  var WeakMapDomCache = class {
8337
8071
  constructor() {
8338
- this.hit = this.miss = this.badKey = 0;
8339
8072
  this.keysByLen = /* @__PURE__ */ new Map();
8340
8073
  }
8341
- _returnValue(r) {
8342
- if (r === void 0) this.miss += 1;
8343
- else this.hit += 1;
8344
- return r;
8345
- }
8346
8074
  get(keys, cacheKey) {
8347
8075
  const len = keys.length;
8348
8076
  let cur = this.keysByLen.get(len);
8349
- if (!cur) return this._returnValue(void 0);
8077
+ if (!cur) return void 0;
8350
8078
  for (let i = 0; i < len - 1; i++) {
8351
8079
  cur = cur.get(keys[i]);
8352
- if (!cur) return this._returnValue(void 0);
8080
+ if (!cur) return void 0;
8353
8081
  }
8354
- return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
8082
+ return cur.get(keys[len - 1])?.[cacheKey];
8355
8083
  }
8356
8084
  set(keys, cacheKey, v) {
8357
8085
  const len = keys.length;
@@ -8364,10 +8092,7 @@ var WeakMapDomCache = class {
8364
8092
  const key = keys[i];
8365
8093
  let next = cur.get(key);
8366
8094
  if (!next) {
8367
- if (!isWeakKey(key)) {
8368
- this.badKey += 1;
8369
- return;
8370
- }
8095
+ if (!isWeakKey(key)) return;
8371
8096
  next = /* @__PURE__ */ new WeakMap();
8372
8097
  cur.set(key, next);
8373
8098
  }
@@ -8377,18 +8102,13 @@ var WeakMapDomCache = class {
8377
8102
  const leaf = cur.get(lastKey);
8378
8103
  if (leaf) leaf[cacheKey] = v;
8379
8104
  else if (isWeakKey(lastKey)) cur.set(lastKey, { [cacheKey]: v });
8380
- else this.badKey += 1;
8381
8105
  }
8382
8106
  evict() {
8383
- const { hit, miss, badKey } = this;
8384
- this.hit = this.miss = this.badKey = 0;
8385
8107
  this.keysByLen = /* @__PURE__ */ new Map();
8386
- return { hit, miss, badKey };
8387
8108
  }
8388
8109
  };
8389
8110
 
8390
8111
  // src/renderer.js
8391
- var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk", "rp"];
8392
8112
  function stampRenderBase(vdom, text) {
8393
8113
  if (vdom instanceof VNode)
8394
8114
  return new VNode(
@@ -8406,7 +8126,14 @@ var Renderer = class {
8406
8126
  constructor(comps) {
8407
8127
  this.comps = comps;
8408
8128
  this.cache = new WeakMapDomCache();
8409
- this.renderTag = h;
8129
+ }
8130
+ // Parse nodes build their VDOM through the renderer, never by importing vdom.js
8131
+ // themselves: a component may have been compiled by ANOTHER copy of the library
8132
+ // (a docs example imports the dist bundle while the host app runs from src), and
8133
+ // `render()` recognizes VNodes by `instanceof` against ITS copy's classes. Going
8134
+ // through `rx` guarantees the rendering copy makes them.
8135
+ renderTag(tag, attrs, childs, namespace) {
8136
+ return h(tag, attrs, childs, namespace);
8410
8137
  }
8411
8138
  renderFragment(childs) {
8412
8139
  return new VFragment(childs);
@@ -8417,30 +8144,16 @@ var Renderer = class {
8417
8144
  setNullCache() {
8418
8145
  this.cache = new NullDomCache();
8419
8146
  }
8420
- // Library utilities for consumers embedding tutuca: render a value to a detached
8421
- // DOM node / an HTML string. Not called by the framework itself.
8422
- renderToDOM(stack, val) {
8423
- const rootNode = document.createElement("div");
8424
- const rOpts = { document };
8425
- render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
8426
- return rootNode.childNodes[0];
8427
- }
8428
- renderToString(stack, val, cleanAttrs = true) {
8429
- const dom = this.renderToDOM(stack, val);
8430
- if (cleanAttrs) {
8431
- const nodes = dom.querySelectorAll("[data-nid],[data-cid],[data-eid]");
8432
- for (const { dataset } of nodes) for (const name of DATASET_ATTRS) delete dataset[name];
8433
- }
8434
- return dom.innerHTML;
8435
- }
8436
8147
  renderRoot(stack, val, viewName = null) {
8437
8148
  const comp = this.comps.getCompFor(val);
8438
8149
  if (comp === null) return null;
8439
8150
  return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
8440
8151
  }
8441
- renderIt(stack, node, key, viewName, base = null) {
8152
+ // Render `stack.it` at a `<x render*>` site (`node`). `base` is the absolute
8153
+ // path the site resumed at, when it rendered a `*name` (see _rValComp).
8154
+ renderIt(stack, node, viewName, base = null) {
8442
8155
  const comp = this.comps.getCompFor(stack.it);
8443
- return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName, base) : null;
8156
+ return comp ? this._rValComp(stack, stack.it, comp, node, "", viewName, base) : null;
8444
8157
  }
8445
8158
  // `node` is the parse node of the render site (`<x render>` / `render-it` /
8446
8159
  // `render-each`, or the view's root anode for the app root). It keys the
@@ -8475,9 +8188,9 @@ var Renderer = class {
8475
8188
  r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
8476
8189
  }
8477
8190
  renderEachWhen(stack, each) {
8478
- const { iterInfo, node: view, nodeId: nid } = each;
8479
- const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
8480
- const seqPath = iterInfo.val instanceof DynVal ? stack.lookupDynamicLocated(iterInfo.val.name)?.path ?? null : null;
8191
+ const { val: seqVal, node: view, nodeId: nid } = each;
8192
+ const { seq, filter, loopWith, enricher } = each.evalIter(stack);
8193
+ const seqPath = seqVal instanceof DynVal ? stack.lookupDynamicLocated(seqVal.name)?.path ?? null : null;
8481
8194
  const r = [];
8482
8195
  const it = stack.it;
8483
8196
  const renderOne = (key, value, attrName, binds) => {
@@ -8641,12 +8354,7 @@ function shadowCheckComponent(Comp) {
8641
8354
  shadowViews[name] = { name, ctx, rawView };
8642
8355
  }
8643
8356
  const shadowComp = Object.create(Comp);
8644
- Object.defineProperty(shadowComp, "views", {
8645
- value: shadowViews,
8646
- writable: true,
8647
- enumerable: true,
8648
- configurable: true
8649
- });
8357
+ shadowComp.views = shadowViews;
8650
8358
  return checkComponent(shadowComp).reports;
8651
8359
  }
8652
8360
  function check(app) {
@@ -8672,39 +8380,6 @@ function check(app) {
8672
8380
  );
8673
8381
  return counts;
8674
8382
  }
8675
- var LintClassCollectorCtx = class _LintClassCollectorCtx extends ParseCtxClassSetCollector {
8676
- constructor(...args) {
8677
- super(...args);
8678
- this.attrs = [];
8679
- this.parseIssues = [];
8680
- }
8681
- enterMacro(macroName, macroVars, macroSlots) {
8682
- const { document: document2, Text, Comment, nodes, events, macroNodes } = this;
8683
- const frame = { macroName, macroVars, macroSlots };
8684
- const v = new _LintClassCollectorCtx(
8685
- document2,
8686
- Text,
8687
- Comment,
8688
- nodes,
8689
- events,
8690
- macroNodes,
8691
- frame,
8692
- this
8693
- );
8694
- v.classes = this.classes;
8695
- v.attrs = this.attrs;
8696
- v.parseIssues = this.parseIssues;
8697
- return v;
8698
- }
8699
- onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false, tag = null) {
8700
- super.onAttributes(attrs, wrapperAttrs, textChild, isMacroCall, tag);
8701
- this.attrs.push({ attrs, wrapperAttrs, textChild, isMacroCall, tag });
8702
- }
8703
- onParseIssue(kind, info) {
8704
- const tag = this.currentTag;
8705
- this.parseIssues.push({ kind, info: tag && info.tag === void 0 ? { ...info, tag } : info });
8706
- }
8707
- };
8708
8383
  var export_expect = chai_exports.expect;
8709
8384
  export {
8710
8385
  ALT_HANDLER_NOT_DEFINED,
@@ -8725,7 +8400,6 @@ export {
8725
8400
  DescribeResult,
8726
8401
  EVENT_HANDLER_METHOD_NOT_ALLOWED,
8727
8402
  ExampleIndex,
8728
- FIELD_CLASS,
8729
8403
  FIELD_METHOD_NAME_COLLISION,
8730
8404
  FIELD_VAL_IS_METHOD,
8731
8405
  FIELD_VAL_NOT_DEFINED,
@@ -8734,7 +8408,6 @@ export {
8734
8408
  IF_NO_BRANCH_SET,
8735
8409
  LOOKUP_BAD_SHAPE,
8736
8410
  LOOKUP_NO_PROVIDER,
8737
- LintClassCollectorCtx,
8738
8411
  LintComponentResult,
8739
8412
  LintContext,
8740
8413
  LintFinding,
@@ -8747,6 +8420,7 @@ export {
8747
8420
  ModuleInfo,
8748
8421
  ModuleTestReport,
8749
8422
  ModuleTests,
8423
+ ORPHAN_DIRECTIVE,
8750
8424
  PASS,
8751
8425
  PLACEHOLDERLESS_TEMPLATE_STRING,
8752
8426
  PROVIDE_NOT_ADDRESSABLE,