tutuca 0.13.1 → 0.13.3

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.
@@ -64,11 +64,6 @@ var writeKey = (value, key, next) => {
64
64
  value.add(next);
65
65
  } else value[key] = next;
66
66
  };
67
- var readSeqKey = (value, key, dval = null) => {
68
- const direct = readKey(value, key, NONE);
69
- if (direct !== NONE) return direct;
70
- return typeof value?.get === "function" ? value.get(key, dval) : dval;
71
- };
72
67
  var writeSeqKey = (value, key, next) => {
73
68
  if (value instanceof Map || value instanceof Set || Array.isArray(value) || Object.hasOwn(value, key))
74
69
  writeKey(value, key, next);
@@ -81,7 +76,7 @@ var Step = class {
81
76
  }
82
77
  setDraftValue(_root, _v) {
83
78
  }
84
- enterFrame(stack, _prev, next) {
79
+ enterFrame(stack, next) {
85
80
  return stack.enter(next, {}, true);
86
81
  }
87
82
  toAbstractPathStep() {
@@ -107,7 +102,7 @@ var BindStep = class _BindStep extends Step {
107
102
  lookup(v, _dval) {
108
103
  return v;
109
104
  }
110
- enterFrame(stack, _prev, next) {
105
+ enterFrame(stack, next) {
111
106
  return stack.enter(next, { ...this.binds }, false);
112
107
  }
113
108
  withIndex(i) {
@@ -125,7 +120,7 @@ var ScopeBindStep = class _ScopeBindStep extends BindStep {
125
120
  super(binds);
126
121
  this.val = val;
127
122
  }
128
- enterFrame(stack, _prev, next) {
123
+ enterFrame(stack, next) {
129
124
  const dyn = this.val.evalAsHandler(stack)?.call(stack.it) ?? {};
130
125
  return stack.enter(next, { ...this.binds, ...dyn }, false);
131
126
  }
@@ -164,13 +159,13 @@ var SeqStep = class extends Step {
164
159
  this.key = key;
165
160
  }
166
161
  lookup(v, dval = null) {
167
- return readSeqKey(readKey(v, this.field, null), this.key, dval);
162
+ return seqGet(readKey(v, this.field, null), this.key, dval);
168
163
  }
169
164
  setDraftValue(root, v) {
170
165
  const seq = readKey(root, this.field, null);
171
166
  if (seq != null) writeSeqKey(seq, this.key, v);
172
167
  }
173
- enterFrame(stack, _prev, next) {
168
+ enterFrame(stack, next) {
174
169
  return stack.enter(next, { key: this.key }, true);
175
170
  }
176
171
  toKey() {
@@ -186,7 +181,7 @@ var SeqAccessStep = class extends Step {
186
181
  lookup(v, dval = null) {
187
182
  const seq = readKey(v, this.seqField, NONE);
188
183
  const key = readKey(v, this.keyField, NONE);
189
- return key !== NONE && seq !== NONE ? readSeqKey(seq, key, dval) : dval;
184
+ return key !== NONE && seq !== NONE ? seqGet(seq, key, dval) : dval;
190
185
  }
191
186
  setDraftValue(root, v) {
192
187
  const seq = readKey(root, this.seqField, NONE);
@@ -217,7 +212,7 @@ var EachBindStep = class extends Step {
217
212
  }
218
213
  // Replay the renderer's per-item binds (key, value + any @enrich-with binds)
219
214
  // so a rebuilt stack matches the one @each rendered with.
220
- enterFrame(stack, _prev, next) {
215
+ enterFrame(stack, next) {
221
216
  return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false);
222
217
  }
223
218
  toAbstractPathStep() {
@@ -225,7 +220,7 @@ var EachBindStep = class extends Step {
225
220
  }
226
221
  };
227
222
  var EachRenderItStep = class extends SeqStep {
228
- enterFrame(stack, _prev, next) {
223
+ enterFrame(stack, next) {
229
224
  return stack.enter(next, { key: this.key, value: next }, false).enter(next, {}, true);
230
225
  }
231
226
  toAbstractPathStep() {
@@ -250,7 +245,7 @@ var DynStep = class extends Step {
250
245
  warnRawDynStep("lookup", this);
251
246
  return dval;
252
247
  }
253
- enterFrame(stack, _prev, _next) {
248
+ enterFrame(stack, _next) {
254
249
  warnRawDynStep("enterFrame", this);
255
250
  return stack;
256
251
  }
@@ -388,7 +383,7 @@ var Path = class _Path {
388
383
  console.warn("bad PathItem", { root: stack.it, step, path: this });
389
384
  return null;
390
385
  }
391
- stack = step.enterFrame(stack, prev, next);
386
+ stack = step.enterFrame(stack, next);
392
387
  prev = next;
393
388
  }
394
389
  return stack;
@@ -458,10 +453,6 @@ var Path = class _Path {
458
453
  console.warn("event reconstruction: dynamic-var producer not found", pendingDyns);
459
454
  return [new _Path(pathSteps.reverse()), handlers];
460
455
  }
461
- static fromEvent(e, rNode, maxDepth, comps, stopOnNoEvent = true) {
462
- const { type, target } = e;
463
- return _Path.fromNodeAndEventName(target, type, rNode, maxDepth, comps, stopOnNoEvent);
464
- }
465
456
  };
466
457
  function metaChain(n) {
467
458
  const out = [];
@@ -665,31 +656,14 @@ function parseBool(s, px) {
665
656
  const val = parseToken(tokens[0], px);
666
657
  return val !== null && kindOf(val) & G_BOOL ? val : null;
667
658
  }
668
- function parseText(s, px) {
669
- return _parseSingle(s, px, G_TEXT);
670
- }
671
- function parseComponent(s, px) {
672
- return _parseSingle(s, px, G_COMPONENT);
673
- }
674
- function parseSequence(s, px) {
675
- return _parseSingle(s, px, G_SEQUENCE);
676
- }
677
- function parseField(s, px) {
678
- return _parseSingle(s, px, G_FIELD);
679
- }
680
- function parseProvide(s, px) {
681
- return _parseSingle(s, px, G_PROVIDE);
682
- }
683
- function parseMacroAttr(s, px) {
684
- return _parseSingle(s, px, G_ALL);
685
- }
686
- function parseReceiveHandler(s, px) {
687
- return _parseHandler(s, px, "receive", true, true, false);
688
- }
689
- function parseAlterHandler(s, px) {
690
- const r = _parseHandler(s, px, "alter", false, false, true);
691
- return r === null ? null : r.handlerVal;
692
- }
659
+ var parseText = (s, px) => _parseSingle(s, px, G_TEXT);
660
+ var parseComponent = (s, px) => _parseSingle(s, px, G_COMPONENT);
661
+ var parseSequence = (s, px) => _parseSingle(s, px, G_SEQUENCE);
662
+ var parseField = (s, px) => _parseSingle(s, px, G_FIELD);
663
+ var parseProvide = (s, px) => _parseSingle(s, px, G_PROVIDE);
664
+ var parseMacroAttr = (s, px) => _parseSingle(s, px, G_ALL);
665
+ var parseReceiveHandler = (s, px) => _parseHandler(s, px, "receive", true, true, false);
666
+ var parseAlterHandler = (s, px) => _parseHandler(s, px, "alter", false, false, true)?.handlerVal ?? null;
693
667
  function _parseHandler(s, px, namespace, allowArgs, report, allowMethod) {
694
668
  const tokens = tokenizeValue(s.trim());
695
669
  const headTok = tokens[0] ?? "";
@@ -1021,7 +995,7 @@ var Attributes = class {
1021
995
  this.items = items;
1022
996
  }
1023
997
  static parse(attributes, px, parseAll = false) {
1024
- return getAttrParser(px).parse(attributes, parseAll);
998
+ return new AttrParser(px).parse(attributes, parseAll);
1025
999
  }
1026
1000
  isConstant() {
1027
1001
  return false;
@@ -1267,9 +1241,6 @@ var IfAttr = class extends BaseAttr {
1267
1241
  return this.condVal.eval(stack) ? this.thenVal.eval(stack) : this.elseVal.eval(stack);
1268
1242
  }
1269
1243
  };
1270
- function getAttrParser(px) {
1271
- return new AttrParser(px);
1272
- }
1273
1244
  var EventHandler = class _EventHandler {
1274
1245
  constructor(handlerVal, args = []) {
1275
1246
  this.handlerVal = handlerVal;
@@ -1285,12 +1256,6 @@ var EventHandler = class _EventHandler {
1285
1256
  return r === null ? null : new _EventHandler(r.handlerVal, r.args);
1286
1257
  }
1287
1258
  };
1288
- var IntentHandler = class {
1289
- constructor(name, fn) {
1290
- this.name = name;
1291
- this.fn = fn;
1292
- }
1293
- };
1294
1259
 
1295
1260
  // src/iteration.js
1296
1261
  var SEQ_INFO = /* @__PURE__ */ Symbol.for("tutuca.seqInfo");
@@ -1341,6 +1306,15 @@ var callEnricher = (enricher, it, binds, key, value, iterData) => {
1341
1306
  binds.key = key;
1342
1307
  binds.value = value;
1343
1308
  };
1309
+ function bindsForKey({ seq, it, loopWith, enricher, ctx }, key) {
1310
+ const value = seqGet(seq, key, null);
1311
+ const binds = { key, value };
1312
+ if (enricher) {
1313
+ const { iterData } = unpackLoopResult(loopWith.call(it, seq, ctx), seq);
1314
+ callEnricher(enricher, it, binds, key, value, iterData);
1315
+ }
1316
+ return binds;
1317
+ }
1344
1318
  var visitKeys = (seq, keys, visit) => {
1345
1319
  const attrName = isIndexedSeq(seq) ? "si" : "sk";
1346
1320
  for (const key of keys) visit(key, seqGet(seq, key), attrName);
@@ -1378,19 +1352,9 @@ function childOpts(vnode, ns, opts) {
1378
1352
  const target = ns === SVG_NS && isForeignObject(vnode.tag) ? null : ns;
1379
1353
  return target === (opts.namespace ?? null) ? opts : { ...opts, namespace: target };
1380
1354
  }
1381
- var NEVER_ASSIGN = /* @__PURE__ */ new Set([
1382
- "width",
1383
- "height",
1384
- "href",
1385
- "list",
1386
- "form",
1387
- "tabIndex",
1388
- "download",
1389
- "rowSpan",
1390
- "colSpan",
1391
- "role",
1392
- "popover"
1393
- ]);
1355
+ var NEVER_ASSIGN = new Set(
1356
+ "width height href list form tabIndex download rowSpan colSpan role popover".split(" ")
1357
+ );
1394
1358
  var PROP_ATTR_NAME = { className: "class", htmlFor: "for" };
1395
1359
  function applyProperties(node, props) {
1396
1360
  const namespaced = isNamespaced(node);
@@ -1669,6 +1633,10 @@ function morphChildren(parentDom, oldChilds, newChilds, opts) {
1669
1633
  if (!used[i] && domNodes[i].parentNode === parentDom) parentDom.removeChild(domNodes[i]);
1670
1634
  }
1671
1635
  function render(vnode, container, options, prev) {
1636
+ if (vnode == null) {
1637
+ container.replaceChildren();
1638
+ return { vnode: null, dom: null };
1639
+ }
1672
1640
  const isFragment = vnode instanceof VFragment;
1673
1641
  if (prev && prev.vnode instanceof VFragment === isFragment) {
1674
1642
  const oldDom = isFragment ? container : prev.dom;
@@ -2185,20 +2153,11 @@ var IterInfo = class {
2185
2153
  const enricher = this.enrichWithVal?.evalAsHandler(stack) ?? null;
2186
2154
  return { seq, filter, loopWith, enricher };
2187
2155
  }
2188
- // Rebuild the per-item binds for `key`, mirroring renderEachWhen: seed
2189
- // { key, value }, then run @enrich-with (with @loop-with's iterData) if any.
2156
+ // Rebuild the per-item binds for `key` (see iteration.js bindsForKey).
2190
2157
  enrichBinds(stack, key) {
2191
2158
  const { seq, filter, loopWith, enricher } = this.eval(stack);
2192
- const value = seqGet(seq, key, null);
2193
- const binds = { key, value };
2194
- if (enricher) {
2195
- const { iterData } = unpackLoopResult(
2196
- loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)),
2197
- seq
2198
- );
2199
- callEnricher(enricher, stack.it, binds, key, value, iterData);
2200
- }
2201
- return binds;
2159
+ const ctx = makeLoopCtx(stack, filter);
2160
+ return bindsForKey({ seq, it: stack.it, loopWith, enricher, ctx }, key);
2202
2161
  }
2203
2162
  };
2204
2163
  function xOp(consumed = [], { wrappable = false, wrapper = null, ignoresChildren = false } = {}) {
@@ -2394,10 +2353,11 @@ var NodeEvent = class {
2394
2353
  }
2395
2354
  };
2396
2355
  var fwdIfCtxPred = (pred) => (w) => (that, f, args, ctx) => pred(ctx) ? w(that, f, args, ctx) : that;
2397
- var fwdIfKey = (keyName) => fwdIfCtxPred((ctx) => ctx.e.key === keyName);
2398
- var fwdCtrl = fwdIfCtxPred(({ e }) => isMac && e.metaKey || e.ctrlKey);
2399
- var fwdMeta = fwdIfCtxPred(({ e }) => e.metaKey);
2400
- var fwdAlt = fwdIfCtxPred(({ e }) => e.altKey);
2356
+ var fwdIfEventPred = (pred) => fwdIfCtxPred(({ e }) => pred(e));
2357
+ var fwdIfKey = (keyName) => fwdIfEventPred(keyIs(keyName));
2358
+ var fwdCtrl = fwdIfEventPred(macCtrl);
2359
+ var fwdMeta = fwdIfEventPred((e) => e.metaKey);
2360
+ var fwdAlt = fwdIfEventPred((e) => e.altKey);
2401
2361
  var MOD_WRAPPERS_FOR_ANY_EVENT = {
2402
2362
  ctrl: fwdCtrl,
2403
2363
  cmd: fwdCtrl,
@@ -2504,13 +2464,15 @@ var ComponentStack = class _ComponentStack {
2504
2464
  getCompFor(v) {
2505
2465
  return this.comps.getCompFor(v);
2506
2466
  }
2507
- // Handlers that answer an intent's `lex` leg. A name maps to a LIST, because the leg
2508
- // walks: a handler that returns PASS declines and hands the intent to the next one.
2509
- // A bare function is accepted as a one-element list.
2467
+ // Handlers that answer an intent's `lex` leg. A name maps to a LIST of plain
2468
+ // functions, because the leg walks: a handler that returns PASS declines and hands
2469
+ // the intent to the next one. Each runs with no `this` and takes a dispatcher
2470
+ // context as its final argument; resolving answers, throwing fails. A bare function
2471
+ // is accepted as a one-element list.
2510
2472
  registerIntentHandlers(handlers) {
2511
2473
  for (const name in handlers) {
2512
- const fns = Array.isArray(handlers[name]) ? handlers[name] : [handlers[name]];
2513
- this.intentsByName[name] = fns.map((fn) => new IntentHandler(name, fn));
2474
+ const fns = handlers[name];
2475
+ this.intentsByName[name] = Array.isArray(fns) ? fns : [fns];
2514
2476
  }
2515
2477
  }
2516
2478
  // Innermost scope first, then outward. Concatenated rather than first-match, so a
@@ -2540,14 +2502,12 @@ var ComponentStack = class _ComponentStack {
2540
2502
  }
2541
2503
  };
2542
2504
  var ProvideInfo = class {
2543
- constructor(name, val) {
2544
- this.name = name;
2505
+ constructor(val) {
2545
2506
  this.val = val;
2546
2507
  }
2547
2508
  };
2548
2509
  var LookupInfo = class {
2549
- constructor(name, val) {
2550
- this.name = name;
2510
+ constructor(val) {
2551
2511
  this.val = val;
2552
2512
  }
2553
2513
  };
@@ -2595,13 +2555,13 @@ var Component = class {
2595
2555
  continue;
2596
2556
  }
2597
2557
  const val = parseProvide(this._rawProvide[key], ctx);
2598
- if (val) this.provide[key] = new ProvideInfo(key, val);
2558
+ if (val) this.provide[key] = new ProvideInfo(val);
2599
2559
  }
2600
2560
  for (const entry of this._rawLookup) {
2601
2561
  const name = isString(entry) ? entry : isString(entry?.name) ? entry.name : null;
2602
2562
  if (name === null) continue;
2603
2563
  const defStr = isString(entry?.default) ? entry.default : null;
2604
- this.lookup[name] = new LookupInfo(name, defStr === null ? null : parseField(defStr, ctx));
2564
+ this.lookup[name] = new LookupInfo(defStr === null ? null : parseField(defStr, ctx));
2605
2565
  }
2606
2566
  for (const key in this.lookup)
2607
2567
  if (this.provide[key] !== void 0)
@@ -2631,7 +2591,7 @@ var Component = class {
2631
2591
  // src/stack.js
2632
2592
  var STOP = /* @__PURE__ */ Symbol("STOP");
2633
2593
  var NEXT = /* @__PURE__ */ Symbol("NEXT");
2634
- var DEFAULT_LOOKUP_ROUTE = ["dyn", "lex"];
2594
+ var DEFAULT_ROUTE = ["dyn", "lex"];
2635
2595
  function routeLookup(route, lex, dyn) {
2636
2596
  for (let i = 0; i < route.length; i++) {
2637
2597
  const leg = route[i];
@@ -2753,20 +2713,6 @@ var Stack = class _Stack {
2753
2713
  lookupBind(name) {
2754
2714
  return lookup(this.binds, name);
2755
2715
  }
2756
- // The `lex` leg: what a name means in the registration scope of the component being
2757
- // rendered. The scope chain holds components, so this leg only ever answers for a
2758
- // type name — for a value name it is a miss, which is why one default route serves
2759
- // both. Guarded: a non-component `it` has no scope to ask.
2760
- _lookupLex(name) {
2761
- return this.comps.getCompFor(this.it)?.scope.lookupComponent(name) ?? null;
2762
- }
2763
- lookupRouted(name, route = DEFAULT_LOOKUP_ROUTE) {
2764
- return routeLookup(
2765
- route,
2766
- () => this._lookupLex(name),
2767
- () => this.lookupDynamic(name)
2768
- );
2769
- }
2770
2716
  lookupFieldRaw(name) {
2771
2717
  return this.it[name] ?? null;
2772
2718
  }
@@ -2799,34 +2745,16 @@ var Stack = class _Stack {
2799
2745
  // src/oo.js
2800
2746
  var BAD_VALUE = /* @__PURE__ */ Symbol("BadValue");
2801
2747
  var nullCoercer = (v) => v;
2802
- function defaultToData(v) {
2803
- if (v instanceof Map) return [...v.entries()];
2804
- if (v instanceof Set) return [...v.values()];
2805
- return v;
2806
- }
2807
2748
  var Field = class {
2808
2749
  constructor(type, name, typeCheck, coercer, defaultValue = null) {
2809
2750
  this.type = type;
2810
2751
  this.name = name;
2811
2752
  this.typeCheck = typeCheck;
2812
2753
  this.coercer = coercer;
2813
- this.checks = [];
2814
2754
  this.defaultValue = defaultValue;
2815
2755
  }
2816
- toDataDef() {
2817
- return { type: this.type, defaultValue: defaultToData(this.defaultValue) };
2818
- }
2819
- getFirstFailingCheck(v) {
2820
- if (!this.typeCheck.isValid(v)) return this.typeCheck;
2821
- for (const check3 of this.checks) if (!check3.isValid(v)) return check3;
2822
- return null;
2823
- }
2824
2756
  isValid(v) {
2825
- return this.getFirstFailingCheck(v) === null;
2826
- }
2827
- addCheck(check3) {
2828
- this.checks.push(check3);
2829
- return this;
2757
+ return this.typeCheck(v);
2830
2758
  }
2831
2759
  coerceOr(v, defaultValue = null) {
2832
2760
  if (this.isValid(v)) return v;
@@ -2837,135 +2765,79 @@ var Field = class {
2837
2765
  return this.coerceOr(v, this.defaultValue);
2838
2766
  }
2839
2767
  };
2840
- var Check = class {
2841
- isValid(_v) {
2842
- return true;
2843
- }
2844
- getMessage(_v) {
2845
- return "Invalid";
2846
- }
2847
- };
2848
- var CheckTypeAny = class extends Check {
2849
- };
2850
- var CHECK_TYPE_ANY = new CheckTypeAny();
2851
- var FnCheck = class extends Check {
2852
- constructor(isValidFn, getMessageFn) {
2853
- super();
2854
- this._isValid = isValidFn;
2855
- this._getMessage = getMessageFn;
2856
- }
2857
- isValid(v) {
2858
- return this._isValid(v);
2859
- }
2860
- getMessage(v) {
2861
- return this._getMessage(v);
2862
- }
2768
+ var CHECK_TYPE_ANY = (_v) => true;
2769
+ var CHECK_TYPE_INT = Number.isInteger;
2770
+ var CHECK_TYPE_FLOAT = Number.isFinite;
2771
+ var CHECK_TYPE_BOOL = (v) => typeof v === "boolean";
2772
+ var CHECK_TYPE_STRING = (v) => typeof v === "string";
2773
+ var CHECK_TYPE_LIST = Array.isArray;
2774
+ var CHECK_TYPE_OBJECT = isPlainObject;
2775
+ var CHECK_TYPE_MAP = (v) => v instanceof Map;
2776
+ var CHECK_TYPE_SET = (v) => v instanceof Set;
2777
+ var COERCE_NONE = (_v) => null;
2778
+ var COERCE_BOOL = (v) => !!v;
2779
+ var COERCE_STRING = (v) => v?.toString?.() ?? "";
2780
+ var COERCE_INT = (v) => Number.isFinite(v) ? Math.trunc(v) : null;
2781
+ var COERCE_LIST = (v) => Array.isArray(v) ? [...v] : null;
2782
+ var COERCE_OBJECT = (v) => isPlainObject(v) ? { ...v } : null;
2783
+ var COERCE_MAP = (v) => {
2784
+ if (v instanceof Map) return new Map(v);
2785
+ if (Array.isArray(v) || isPlainObject(v))
2786
+ return new Map(Array.isArray(v) ? v : Object.entries(v));
2787
+ return null;
2863
2788
  };
2864
- var check = (fn, message) => new FnCheck(fn, () => message);
2865
- var CHECK_TYPE_INT = check(Number.isInteger, "Integer expected");
2866
- var CHECK_TYPE_FLOAT = check(Number.isFinite, "Float expected");
2867
- var CHECK_TYPE_BOOL = check((v) => typeof v === "boolean", "Boolean expected");
2868
- var CHECK_TYPE_STRING = check((v) => typeof v === "string", "String expected");
2869
- var CHECK_TYPE_LIST = check(Array.isArray, "Array expected");
2870
- var CHECK_TYPE_OBJECT = check(isPlainObject, "Plain object expected");
2871
- var CHECK_TYPE_MAP = check((v) => v instanceof Map, "Map expected");
2872
- var CHECK_TYPE_SET = check((v) => v instanceof Set, "Set expected");
2789
+ var COERCE_SET = (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null;
2873
2790
  var FieldBool = class extends Field {
2874
2791
  constructor(name, defaultValue = false) {
2875
- super("bool", name, CHECK_TYPE_BOOL, (v) => !!v, defaultValue);
2792
+ super("bool", name, CHECK_TYPE_BOOL, COERCE_BOOL, defaultValue);
2876
2793
  }
2877
2794
  };
2878
2795
  var FieldAny = class extends Field {
2879
2796
  constructor(name, defaultValue = null) {
2880
2797
  super("any", name, CHECK_TYPE_ANY, nullCoercer, defaultValue);
2881
2798
  }
2882
- toDataDef() {
2883
- return { type: getTypeName(this.defaultValue) ?? "any", defaultValue: this.defaultValue };
2884
- }
2885
2799
  };
2886
2800
  var FieldString = class extends Field {
2887
2801
  constructor(name, defaultValue = "") {
2888
- super("text", name, CHECK_TYPE_STRING, (v) => v?.toString?.() ?? "", defaultValue);
2802
+ super("text", name, CHECK_TYPE_STRING, COERCE_STRING, defaultValue);
2889
2803
  }
2890
2804
  };
2891
2805
  var FieldInt = class extends Field {
2892
2806
  constructor(name, defaultValue = 0) {
2893
- super(
2894
- "int",
2895
- name,
2896
- CHECK_TYPE_INT,
2897
- (v) => Number.isFinite(v) ? Math.trunc(v) : null,
2898
- defaultValue
2899
- );
2807
+ super("int", name, CHECK_TYPE_INT, COERCE_INT, defaultValue);
2900
2808
  }
2901
2809
  };
2902
2810
  var FieldFloat = class extends Field {
2903
2811
  constructor(name, defaultValue = 0) {
2904
- super("float", name, CHECK_TYPE_FLOAT, (_) => null, defaultValue);
2905
- }
2906
- };
2907
- var getTypeName = (v) => v?.constructor?.[COMPONENT]?.name ?? v?.constructor?.getMetaClass?.()?.name ?? null;
2908
- var CheckTypeName = class {
2909
- constructor(typeName) {
2910
- this.typeName = typeName;
2911
- }
2912
- isValid(v) {
2913
- return getTypeName(v) === this.typeName;
2914
- }
2915
- getMessage(v) {
2916
- return `Expected "${this.typeName}", got "${getTypeName(v)}"`;
2812
+ super("float", name, CHECK_TYPE_FLOAT, COERCE_NONE, defaultValue);
2917
2813
  }
2918
2814
  };
2815
+ var metaOf = (v) => v?.constructor?.[COMPONENT] ?? v?.constructor?.getMetaClass?.();
2816
+ var getTypeName = (v) => metaOf(v)?.name ?? null;
2919
2817
  var FieldComp = class extends Field {
2920
2818
  constructor(type, name, args) {
2921
- super(type, name, new CheckTypeName(type), nullCoercer, null);
2819
+ super(type, name, (v) => getTypeName(v) === type, nullCoercer, null);
2922
2820
  this.args = args;
2923
2821
  }
2924
- toDataDef() {
2925
- return { component: this.type, args: this.args };
2926
- }
2927
2822
  };
2928
2823
  var FieldList = class extends Field {
2929
2824
  constructor(name, defaultValue = []) {
2930
- super("list", name, CHECK_TYPE_LIST, (v) => Array.isArray(v) ? [...v] : null, defaultValue);
2825
+ super("list", name, CHECK_TYPE_LIST, COERCE_LIST, defaultValue);
2931
2826
  }
2932
2827
  };
2933
2828
  var FieldObject = class extends Field {
2934
2829
  constructor(name, defaultValue = {}) {
2935
- super(
2936
- "object",
2937
- name,
2938
- CHECK_TYPE_OBJECT,
2939
- (v) => isPlainObject(v) ? { ...v } : null,
2940
- defaultValue
2941
- );
2830
+ super("object", name, CHECK_TYPE_OBJECT, COERCE_OBJECT, defaultValue);
2942
2831
  }
2943
2832
  };
2944
2833
  var FieldMap = class extends Field {
2945
2834
  constructor(name, defaultValue = /* @__PURE__ */ new Map()) {
2946
- super(
2947
- "map",
2948
- name,
2949
- CHECK_TYPE_MAP,
2950
- (v) => {
2951
- if (v instanceof Map) return new Map(v);
2952
- if (Array.isArray(v) || isPlainObject(v))
2953
- return new Map(Array.isArray(v) ? v : Object.entries(v));
2954
- return null;
2955
- },
2956
- defaultValue
2957
- );
2835
+ super("map", name, CHECK_TYPE_MAP, COERCE_MAP, defaultValue);
2958
2836
  }
2959
2837
  };
2960
2838
  var FieldSet = class extends Field {
2961
2839
  constructor(name, defaultValue = /* @__PURE__ */ new Set()) {
2962
- super(
2963
- "set",
2964
- name,
2965
- CHECK_TYPE_SET,
2966
- (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null,
2967
- defaultValue
2968
- );
2840
+ super("set", name, CHECK_TYPE_SET, COERCE_SET, defaultValue);
2969
2841
  }
2970
2842
  };
2971
2843
  function mkCompField(field, scope, args) {
@@ -3063,8 +2935,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
3063
2935
  const value = fields[field];
3064
2936
  const type = typeof value;
3065
2937
  if (type === "string") b.addField(field, value, FieldString);
3066
- else if (type === "number")
3067
- b.addField(field, value, Number.isInteger(value) ? FieldInt : FieldFloat);
2938
+ else if (type === "number") b.addField(field, value, FieldFloat);
3068
2939
  else if (type === "boolean") b.addField(field, value, FieldBool);
3069
2940
  else if (Array.isArray(value)) b.addField(field, [...value], FieldList);
3070
2941
  else if (value instanceof Set) b.addField(field, new Set(value), FieldSet);
@@ -3085,7 +2956,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
3085
2956
  return b.build();
3086
2957
  }
3087
2958
  function validateDraftFields(current, draft) {
3088
- const meta = current?.constructor?.[COMPONENT] ?? current?.constructor?.getMetaClass?.();
2959
+ const meta = metaOf(current);
3089
2960
  if (!meta) return;
3090
2961
  for (const [name, field] of Object.entries(meta.fields)) {
3091
2962
  const value = draft[name];
@@ -3212,28 +3083,46 @@ var Transactor = class {
3212
3083
  if (i !== -1) this._refusalObservers.splice(i, 1);
3213
3084
  };
3214
3085
  }
3215
- // Build and dispatch the observer record for a settled transaction. The
3216
- // resolved handler (`_resolvedHandler`/`_matched`) and per-leaf before/after
3217
- // (`_before`/`_after`) were captured while the handler ran (see callHandler /
3218
- // Transaction.run). No-op when nobody is observing.
3086
+ // Build and dispatch one observer record. Pins field-resolved keys (e.g. a
3087
+ // `.a[.selId]` render target reconstructed from a DOM event) against the root the
3088
+ // handler read, so pathKeys carries concrete keys instead of dropping the dynamic
3089
+ // step. No-op when nobody is observing.
3090
+ _emitRecord(root, { kind, name, args, path, targetPath, handler, handlerName, matched, before, after, parent }) {
3091
+ if (this._observers.length === 0) return;
3092
+ const pinned = path.pinKeys(root);
3093
+ this._emit({
3094
+ kind,
3095
+ name,
3096
+ args: args ?? null,
3097
+ path: pinned,
3098
+ pathKeys: pinned.toKeys(),
3099
+ targetPath,
3100
+ handler: handler ?? null,
3101
+ handlerName: handlerName ?? (handler?.name || null),
3102
+ matched: matched ?? null,
3103
+ before,
3104
+ after,
3105
+ parent,
3106
+ timestamp: Date.now()
3107
+ });
3108
+ }
3109
+ // The observer record for a settled transaction. The resolved handler
3110
+ // (`_resolvedHandler`/`_matched`) and per-leaf before/after (`_before`/`_after`)
3111
+ // were captured while the handler ran (see callHandler / Transaction.run).
3219
3112
  _emitTransaction(transaction, root) {
3220
3113
  if (this._observers.length === 0) return;
3221
3114
  if (transaction._resolvedHandler === void 0) return;
3222
- const path = transaction.getTransactionPath().pinKeys(root);
3223
- this._emit({
3115
+ this._emitRecord(root, {
3224
3116
  kind: transaction.observeKind,
3225
3117
  name: transaction.observeName,
3226
- args: transaction.args ?? null,
3227
- path,
3228
- pathKeys: path.toKeys(),
3118
+ args: transaction.args,
3119
+ path: transaction.getTransactionPath(),
3229
3120
  targetPath: transaction.targetPath ?? transaction.path,
3230
- handler: transaction._resolvedHandler ?? null,
3231
- handlerName: transaction._resolvedHandler?.name || null,
3232
- matched: transaction._matched ?? null,
3121
+ handler: transaction._resolvedHandler,
3122
+ matched: transaction._matched,
3233
3123
  before: transaction._before,
3234
3124
  after: transaction._after,
3235
- parent: transaction.parentTransaction,
3236
- timestamp: Date.now()
3125
+ parent: transaction.parentTransaction
3237
3126
  });
3238
3127
  }
3239
3128
  // Make `child` a tracked unit of `parent`'s subtree: the parent's completion stays open
@@ -3331,7 +3220,7 @@ var Transaction = class {
3331
3220
  // rather than throwing, so a stray call from the wrong place is a message and not a
3332
3221
  // crash. `walk` is undefined here, which is how ctx.reply/ctx.fail tell the two apart.
3333
3222
  stop() {
3334
- console.warn('ctx.stop() is only meaningful in an "intent" handler - ignored');
3223
+ warnNotIntent("stop");
3335
3224
  }
3336
3225
  forward(_opts) {
3337
3226
  console.warn('ctx.forward() needs a "receive" or "intent" handler - ignored');
@@ -3416,11 +3305,8 @@ var InputEvent = class extends Transaction {
3416
3305
  }
3417
3306
  this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
3418
3307
  }
3419
- buildStack(root, comps) {
3420
- return this.path.toTransactionPath().buildStack(Stack.root(comps, root, this));
3421
- }
3422
3308
  getHandlerAndArgs(root, _instance, comps) {
3423
- const stack = this.buildStack(root, comps);
3309
+ const stack = this.path.toTransactionPath().buildStack(Stack.root(comps, root, this));
3424
3310
  const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
3425
3311
  this._handlerArgs = [...args];
3426
3312
  const path = this.dispatchPath;
@@ -3522,7 +3408,6 @@ var IntentEvent = class extends NameArgsTransaction {
3522
3408
  };
3523
3409
  var PASS = /* @__PURE__ */ Symbol.for("tutuca.intent.pass");
3524
3410
  var REFUSAL_RING_CAP = 200;
3525
- var DEFAULT_ROUTE = ["dyn", "lex"];
3526
3411
  var INTENT_DEPTH = 64;
3527
3412
  var IntentWalk = class {
3528
3413
  constructor(transactor, path, name, args, opts, parent, release) {
@@ -3571,24 +3456,19 @@ var IntentWalk = class {
3571
3456
  const txnPath = this.origin.toTransactionPath();
3572
3457
  const leaf = txnPath.lookup(root);
3573
3458
  const chain = this.transactor.comps.getIntentChainFor(leaf, this.name);
3574
- if (this.transactor._observers.length > 0) {
3575
- const path = txnPath.pinKeys(root);
3576
- this.transactor._emit({
3577
- kind: "intent",
3578
- name: this.name,
3579
- args: this.args,
3580
- path,
3581
- pathKeys: path.toKeys(),
3582
- targetPath: this.origin,
3583
- handler: chain[0]?.fn ?? null,
3584
- handlerName: chain[0]?.fn?.name || this.name,
3585
- matched: chain.length > 0 ? "exact" : "none",
3586
- before: leaf,
3587
- after: void 0,
3588
- parent: this.parent,
3589
- timestamp: Date.now()
3590
- });
3591
- }
3459
+ this.transactor._emitRecord(root, {
3460
+ kind: "intent",
3461
+ name: this.name,
3462
+ args: this.args,
3463
+ path: txnPath,
3464
+ targetPath: this.origin,
3465
+ handler: chain[0],
3466
+ handlerName: chain[0]?.name || this.name,
3467
+ matched: chain.length > 0 ? "exact" : "none",
3468
+ before: leaf,
3469
+ after: void 0,
3470
+ parent: this.parent
3471
+ });
3592
3472
  if (chain.length === 0) return this.advance();
3593
3473
  const p = this._runLex(chain, 0);
3594
3474
  this.transactor._inflight.add(p);
@@ -3599,7 +3479,7 @@ var IntentWalk = class {
3599
3479
  if (i >= chain.length) return this.advance();
3600
3480
  const ctx = new Dispatcher(this.origin, this.transactor, this.parent);
3601
3481
  try {
3602
- const res = await chain[i].fn.apply(null, [...this.args, ctx]);
3482
+ const res = await chain[i].apply(null, [...this.args, ctx]);
3603
3483
  if (res === PASS) return this._runLex(chain, i + 1);
3604
3484
  this.answer("Ok", res);
3605
3485
  } catch (error) {
@@ -3752,9 +3632,8 @@ var Dispatcher = class {
3752
3632
  // the same spelling as `ctx.intent` — `["dyn"]` the render ancestry, `["lex"]` the
3753
3633
  // registration scope, default both.
3754
3634
  lookup(name, opts) {
3755
- const route = opts?.route ?? DEFAULT_LOOKUP_ROUTE;
3756
3635
  return routeLookup(
3757
- route,
3636
+ opts?.route ?? DEFAULT_ROUTE,
3758
3637
  () => this._lookupLex(name),
3759
3638
  () => this._stack()?.lookupDynamic(name) ?? null
3760
3639
  );
@@ -3773,12 +3652,10 @@ var Dispatcher = class {
3773
3652
  // can only ever answer with one; the `dyn` leg reads a binding an ancestor
3774
3653
  // published, so it is the leg that has to be checked.
3775
3654
  lookupType(name, opts) {
3776
- const v = this.lookup(name, opts);
3655
+ const route = opts?.route ?? DEFAULT_ROUTE;
3656
+ const v = this.lookup(name, { route });
3777
3657
  if (v == null) {
3778
- this.transactor.refuse("TYPE_NOT_FOUND", {
3779
- name,
3780
- route: opts?.route ?? DEFAULT_LOOKUP_ROUTE
3781
- });
3658
+ this.transactor.refuse("TYPE_NOT_FOUND", { name, route });
3782
3659
  return null;
3783
3660
  }
3784
3661
  if (v?.[COMPONENT] == null) {
@@ -3903,7 +3780,14 @@ var App = class {
3903
3780
  const { type } = e;
3904
3781
  const isDrag = type === "dragover" || type === "dragstart" || type === "dragend" || type === "drop";
3905
3782
  const { rootNode: root, maxEventNodeDepth: maxDepth, comps, transactor } = this;
3906
- const [path, handlers] = Path.fromEvent(e, root, maxDepth, comps, !isDrag);
3783
+ const [path, handlers] = Path.fromNodeAndEventName(
3784
+ e.target,
3785
+ type,
3786
+ root,
3787
+ maxDepth,
3788
+ comps,
3789
+ !isDrag
3790
+ );
3907
3791
  if (isDrag) this._handleDragEvent(e, type, path);
3908
3792
  if (path !== null && handlers !== null)
3909
3793
  for (const handler of handlers) transactor.transactInputNow(path, e, handler, this.dragInfo);
@@ -3965,7 +3849,7 @@ var App = class {
3965
3849
  const value = txnPath.lookup(rootValue);
3966
3850
  const dragType = e.target.dataset.dragtype ?? "?";
3967
3851
  const stack = path.toTransactionPath().buildStack(this.makeStack(rootValue));
3968
- this.dragInfo = new DragInfo(txnPath, stack, e, value, dragType, e.target);
3852
+ this.dragInfo = new DragInfo(stack, value, dragType, e.target);
3969
3853
  } else if (type === "drop") {
3970
3854
  e.preventDefault();
3971
3855
  this._cleanDragOverAttrs();
@@ -4102,10 +3986,8 @@ function getClosestDropTarget(target, rootNode, count) {
4102
3986
  return null;
4103
3987
  }
4104
3988
  var DragInfo = class {
4105
- constructor(path, stack, e, val, type, node) {
4106
- this.path = path;
3989
+ constructor(stack, val, type, node) {
4107
3990
  this.stack = stack;
4108
- this.e = e;
4109
3991
  this.val = val;
4110
3992
  this.type = type;
4111
3993
  this.node = node;
@@ -4197,6 +4079,8 @@ var Renderer = class {
4197
4079
  setNullCache() {
4198
4080
  this.cache = new NullDomCache();
4199
4081
  }
4082
+ // Library utilities for consumers embedding tutuca: render a value to a detached
4083
+ // DOM node / an HTML string. Not called by the framework itself.
4200
4084
  renderToDOM(stack, val) {
4201
4085
  const rootNode = document.createElement("div");
4202
4086
  const rOpts = { document };
@@ -4321,7 +4205,7 @@ function dispatchPhase(dispatcher, targetPath, phase, self) {
4321
4205
  var css = String.raw;
4322
4206
  var html = String.raw;
4323
4207
  var macro = (defaults, rawView) => new Macro(defaults, rawView);
4324
- function check2(_app) {
4208
+ function check(_app) {
4325
4209
  return { error: 0, warn: 0, hint: 0, dummyCheck: true };
4326
4210
  }
4327
4211
  async function test(_opts) {
@@ -4345,7 +4229,7 @@ export {
4345
4229
  PASS,
4346
4230
  ParseContext,
4347
4231
  SEQ_INFO,
4348
- check2 as check,
4232
+ check,
4349
4233
  collectIterBindings,
4350
4234
  component,
4351
4235
  css,