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.
package/dist/tutuca.js CHANGED
@@ -767,11 +767,6 @@ var writeKey = (value, key, next) => {
767
767
  value.add(next);
768
768
  } else value[key] = next;
769
769
  };
770
- var readSeqKey = (value, key, dval = null) => {
771
- const direct = readKey(value, key, NONE);
772
- if (direct !== NONE) return direct;
773
- return typeof value?.get === "function" ? value.get(key, dval) : dval;
774
- };
775
770
  var writeSeqKey = (value, key, next) => {
776
771
  if (value instanceof Map || value instanceof Set || Array.isArray(value) || Object.hasOwn(value, key))
777
772
  writeKey(value, key, next);
@@ -784,7 +779,7 @@ var Step = class {
784
779
  }
785
780
  setDraftValue(_root, _v) {
786
781
  }
787
- enterFrame(stack, _prev, next) {
782
+ enterFrame(stack, next) {
788
783
  return stack.enter(next, {}, true);
789
784
  }
790
785
  toAbstractPathStep() {
@@ -810,7 +805,7 @@ var BindStep = class _BindStep extends Step {
810
805
  lookup(v, _dval) {
811
806
  return v;
812
807
  }
813
- enterFrame(stack, _prev, next) {
808
+ enterFrame(stack, next) {
814
809
  return stack.enter(next, { ...this.binds }, false);
815
810
  }
816
811
  withIndex(i) {
@@ -828,7 +823,7 @@ var ScopeBindStep = class _ScopeBindStep extends BindStep {
828
823
  super(binds);
829
824
  this.val = val;
830
825
  }
831
- enterFrame(stack, _prev, next) {
826
+ enterFrame(stack, next) {
832
827
  const dyn = this.val.evalAsHandler(stack)?.call(stack.it) ?? {};
833
828
  return stack.enter(next, { ...this.binds, ...dyn }, false);
834
829
  }
@@ -867,13 +862,13 @@ var SeqStep = class extends Step {
867
862
  this.key = key;
868
863
  }
869
864
  lookup(v, dval = null) {
870
- return readSeqKey(readKey(v, this.field, null), this.key, dval);
865
+ return seqGet(readKey(v, this.field, null), this.key, dval);
871
866
  }
872
867
  setDraftValue(root, v) {
873
868
  const seq = readKey(root, this.field, null);
874
869
  if (seq != null) writeSeqKey(seq, this.key, v);
875
870
  }
876
- enterFrame(stack, _prev, next) {
871
+ enterFrame(stack, next) {
877
872
  return stack.enter(next, { key: this.key }, true);
878
873
  }
879
874
  toKey() {
@@ -889,7 +884,7 @@ var SeqAccessStep = class extends Step {
889
884
  lookup(v, dval = null) {
890
885
  const seq = readKey(v, this.seqField, NONE);
891
886
  const key = readKey(v, this.keyField, NONE);
892
- return key !== NONE && seq !== NONE ? readSeqKey(seq, key, dval) : dval;
887
+ return key !== NONE && seq !== NONE ? seqGet(seq, key, dval) : dval;
893
888
  }
894
889
  setDraftValue(root, v) {
895
890
  const seq = readKey(root, this.seqField, NONE);
@@ -920,7 +915,7 @@ var EachBindStep = class extends Step {
920
915
  }
921
916
  // Replay the renderer's per-item binds (key, value + any @enrich-with binds)
922
917
  // so a rebuilt stack matches the one @each rendered with.
923
- enterFrame(stack, _prev, next) {
918
+ enterFrame(stack, next) {
924
919
  return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false);
925
920
  }
926
921
  toAbstractPathStep() {
@@ -928,7 +923,7 @@ var EachBindStep = class extends Step {
928
923
  }
929
924
  };
930
925
  var EachRenderItStep = class extends SeqStep {
931
- enterFrame(stack, _prev, next) {
926
+ enterFrame(stack, next) {
932
927
  return stack.enter(next, { key: this.key, value: next }, false).enter(next, {}, true);
933
928
  }
934
929
  toAbstractPathStep() {
@@ -953,7 +948,7 @@ var DynStep = class extends Step {
953
948
  warnRawDynStep("lookup", this);
954
949
  return dval;
955
950
  }
956
- enterFrame(stack, _prev, _next) {
951
+ enterFrame(stack, _next) {
957
952
  warnRawDynStep("enterFrame", this);
958
953
  return stack;
959
954
  }
@@ -1091,7 +1086,7 @@ var Path = class _Path {
1091
1086
  console.warn("bad PathItem", { root: stack.it, step, path: this });
1092
1087
  return null;
1093
1088
  }
1094
- stack = step.enterFrame(stack, prev, next);
1089
+ stack = step.enterFrame(stack, next);
1095
1090
  prev = next;
1096
1091
  }
1097
1092
  return stack;
@@ -1161,10 +1156,6 @@ var Path = class _Path {
1161
1156
  console.warn("event reconstruction: dynamic-var producer not found", pendingDyns);
1162
1157
  return [new _Path(pathSteps.reverse()), handlers];
1163
1158
  }
1164
- static fromEvent(e, rNode, maxDepth, comps, stopOnNoEvent = true) {
1165
- const { type, target } = e;
1166
- return _Path.fromNodeAndEventName(target, type, rNode, maxDepth, comps, stopOnNoEvent);
1167
- }
1168
1159
  };
1169
1160
  function metaChain(n) {
1170
1161
  const out = [];
@@ -1368,31 +1359,14 @@ function parseBool(s, px) {
1368
1359
  const val = parseToken(tokens[0], px);
1369
1360
  return val !== null && kindOf(val) & G_BOOL ? val : null;
1370
1361
  }
1371
- function parseText(s, px) {
1372
- return _parseSingle(s, px, G_TEXT);
1373
- }
1374
- function parseComponent(s, px) {
1375
- return _parseSingle(s, px, G_COMPONENT);
1376
- }
1377
- function parseSequence(s, px) {
1378
- return _parseSingle(s, px, G_SEQUENCE);
1379
- }
1380
- function parseField(s, px) {
1381
- return _parseSingle(s, px, G_FIELD);
1382
- }
1383
- function parseProvide(s, px) {
1384
- return _parseSingle(s, px, G_PROVIDE);
1385
- }
1386
- function parseMacroAttr(s, px) {
1387
- return _parseSingle(s, px, G_ALL);
1388
- }
1389
- function parseReceiveHandler(s, px) {
1390
- return _parseHandler(s, px, "receive", true, true, false);
1391
- }
1392
- function parseAlterHandler(s, px) {
1393
- const r = _parseHandler(s, px, "alter", false, false, true);
1394
- return r === null ? null : r.handlerVal;
1395
- }
1362
+ var parseText = (s, px) => _parseSingle(s, px, G_TEXT);
1363
+ var parseComponent = (s, px) => _parseSingle(s, px, G_COMPONENT);
1364
+ var parseSequence = (s, px) => _parseSingle(s, px, G_SEQUENCE);
1365
+ var parseField = (s, px) => _parseSingle(s, px, G_FIELD);
1366
+ var parseProvide = (s, px) => _parseSingle(s, px, G_PROVIDE);
1367
+ var parseMacroAttr = (s, px) => _parseSingle(s, px, G_ALL);
1368
+ var parseReceiveHandler = (s, px) => _parseHandler(s, px, "receive", true, true, false);
1369
+ var parseAlterHandler = (s, px) => _parseHandler(s, px, "alter", false, false, true)?.handlerVal ?? null;
1396
1370
  function _parseHandler(s, px, namespace, allowArgs, report, allowMethod) {
1397
1371
  const tokens = tokenizeValue(s.trim());
1398
1372
  const headTok = tokens[0] ?? "";
@@ -1724,7 +1698,7 @@ var Attributes = class {
1724
1698
  this.items = items;
1725
1699
  }
1726
1700
  static parse(attributes, px, parseAll = false) {
1727
- return getAttrParser(px).parse(attributes, parseAll);
1701
+ return new AttrParser(px).parse(attributes, parseAll);
1728
1702
  }
1729
1703
  isConstant() {
1730
1704
  return false;
@@ -1970,9 +1944,6 @@ var IfAttr = class extends BaseAttr {
1970
1944
  return this.condVal.eval(stack) ? this.thenVal.eval(stack) : this.elseVal.eval(stack);
1971
1945
  }
1972
1946
  };
1973
- function getAttrParser(px) {
1974
- return new AttrParser(px);
1975
- }
1976
1947
  var EventHandler = class _EventHandler {
1977
1948
  constructor(handlerVal, args = []) {
1978
1949
  this.handlerVal = handlerVal;
@@ -1988,12 +1959,6 @@ var EventHandler = class _EventHandler {
1988
1959
  return r === null ? null : new _EventHandler(r.handlerVal, r.args);
1989
1960
  }
1990
1961
  };
1991
- var IntentHandler = class {
1992
- constructor(name, fn) {
1993
- this.name = name;
1994
- this.fn = fn;
1995
- }
1996
- };
1997
1962
 
1998
1963
  // src/iteration.js
1999
1964
  var SEQ_INFO = /* @__PURE__ */ Symbol.for("tutuca.seqInfo");
@@ -2044,6 +2009,15 @@ var callEnricher = (enricher, it, binds, key, value, iterData) => {
2044
2009
  binds.key = key;
2045
2010
  binds.value = value;
2046
2011
  };
2012
+ function bindsForKey({ seq, it, loopWith, enricher, ctx }, key) {
2013
+ const value = seqGet(seq, key, null);
2014
+ const binds = { key, value };
2015
+ if (enricher) {
2016
+ const { iterData } = unpackLoopResult(loopWith.call(it, seq, ctx), seq);
2017
+ callEnricher(enricher, it, binds, key, value, iterData);
2018
+ }
2019
+ return binds;
2020
+ }
2047
2021
  var visitKeys = (seq, keys, visit) => {
2048
2022
  const attrName = isIndexedSeq(seq) ? "si" : "sk";
2049
2023
  for (const key of keys) visit(key, seqGet(seq, key), attrName);
@@ -2081,19 +2055,9 @@ function childOpts(vnode, ns, opts) {
2081
2055
  const target = ns === SVG_NS && isForeignObject(vnode.tag) ? null : ns;
2082
2056
  return target === (opts.namespace ?? null) ? opts : { ...opts, namespace: target };
2083
2057
  }
2084
- var NEVER_ASSIGN = /* @__PURE__ */ new Set([
2085
- "width",
2086
- "height",
2087
- "href",
2088
- "list",
2089
- "form",
2090
- "tabIndex",
2091
- "download",
2092
- "rowSpan",
2093
- "colSpan",
2094
- "role",
2095
- "popover"
2096
- ]);
2058
+ var NEVER_ASSIGN = new Set(
2059
+ "width height href list form tabIndex download rowSpan colSpan role popover".split(" ")
2060
+ );
2097
2061
  var PROP_ATTR_NAME = { className: "class", htmlFor: "for" };
2098
2062
  function applyProperties(node, props) {
2099
2063
  const namespaced = isNamespaced(node);
@@ -2372,6 +2336,10 @@ function morphChildren(parentDom, oldChilds, newChilds, opts) {
2372
2336
  if (!used[i] && domNodes[i].parentNode === parentDom) parentDom.removeChild(domNodes[i]);
2373
2337
  }
2374
2338
  function render(vnode, container, options, prev) {
2339
+ if (vnode == null) {
2340
+ container.replaceChildren();
2341
+ return { vnode: null, dom: null };
2342
+ }
2375
2343
  const isFragment = vnode instanceof VFragment;
2376
2344
  if (prev && prev.vnode instanceof VFragment === isFragment) {
2377
2345
  const oldDom = isFragment ? container : prev.dom;
@@ -2888,20 +2856,11 @@ var IterInfo = class {
2888
2856
  const enricher = this.enrichWithVal?.evalAsHandler(stack) ?? null;
2889
2857
  return { seq, filter, loopWith, enricher };
2890
2858
  }
2891
- // Rebuild the per-item binds for `key`, mirroring renderEachWhen: seed
2892
- // { key, value }, then run @enrich-with (with @loop-with's iterData) if any.
2859
+ // Rebuild the per-item binds for `key` (see iteration.js bindsForKey).
2893
2860
  enrichBinds(stack, key) {
2894
2861
  const { seq, filter, loopWith, enricher } = this.eval(stack);
2895
- const value = seqGet(seq, key, null);
2896
- const binds = { key, value };
2897
- if (enricher) {
2898
- const { iterData } = unpackLoopResult(
2899
- loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)),
2900
- seq
2901
- );
2902
- callEnricher(enricher, stack.it, binds, key, value, iterData);
2903
- }
2904
- return binds;
2862
+ const ctx = makeLoopCtx(stack, filter);
2863
+ return bindsForKey({ seq, it: stack.it, loopWith, enricher, ctx }, key);
2905
2864
  }
2906
2865
  };
2907
2866
  function xOp(consumed = [], { wrappable = false, wrapper = null, ignoresChildren = false } = {}) {
@@ -3097,10 +3056,11 @@ var NodeEvent = class {
3097
3056
  }
3098
3057
  };
3099
3058
  var fwdIfCtxPred = (pred) => (w) => (that, f, args, ctx) => pred(ctx) ? w(that, f, args, ctx) : that;
3100
- var fwdIfKey = (keyName) => fwdIfCtxPred((ctx) => ctx.e.key === keyName);
3101
- var fwdCtrl = fwdIfCtxPred(({ e }) => isMac && e.metaKey || e.ctrlKey);
3102
- var fwdMeta = fwdIfCtxPred(({ e }) => e.metaKey);
3103
- var fwdAlt = fwdIfCtxPred(({ e }) => e.altKey);
3059
+ var fwdIfEventPred = (pred) => fwdIfCtxPred(({ e }) => pred(e));
3060
+ var fwdIfKey = (keyName) => fwdIfEventPred(keyIs(keyName));
3061
+ var fwdCtrl = fwdIfEventPred(macCtrl);
3062
+ var fwdMeta = fwdIfEventPred((e) => e.metaKey);
3063
+ var fwdAlt = fwdIfEventPred((e) => e.altKey);
3104
3064
  var MOD_WRAPPERS_FOR_ANY_EVENT = {
3105
3065
  ctrl: fwdCtrl,
3106
3066
  cmd: fwdCtrl,
@@ -3207,13 +3167,15 @@ var ComponentStack = class _ComponentStack {
3207
3167
  getCompFor(v) {
3208
3168
  return this.comps.getCompFor(v);
3209
3169
  }
3210
- // Handlers that answer an intent's `lex` leg. A name maps to a LIST, because the leg
3211
- // walks: a handler that returns PASS declines and hands the intent to the next one.
3212
- // A bare function is accepted as a one-element list.
3170
+ // Handlers that answer an intent's `lex` leg. A name maps to a LIST of plain
3171
+ // functions, because the leg walks: a handler that returns PASS declines and hands
3172
+ // the intent to the next one. Each runs with no `this` and takes a dispatcher
3173
+ // context as its final argument; resolving answers, throwing fails. A bare function
3174
+ // is accepted as a one-element list.
3213
3175
  registerIntentHandlers(handlers) {
3214
3176
  for (const name in handlers) {
3215
- const fns = Array.isArray(handlers[name]) ? handlers[name] : [handlers[name]];
3216
- this.intentsByName[name] = fns.map((fn) => new IntentHandler(name, fn));
3177
+ const fns = handlers[name];
3178
+ this.intentsByName[name] = Array.isArray(fns) ? fns : [fns];
3217
3179
  }
3218
3180
  }
3219
3181
  // Innermost scope first, then outward. Concatenated rather than first-match, so a
@@ -3243,14 +3205,12 @@ var ComponentStack = class _ComponentStack {
3243
3205
  }
3244
3206
  };
3245
3207
  var ProvideInfo = class {
3246
- constructor(name, val) {
3247
- this.name = name;
3208
+ constructor(val) {
3248
3209
  this.val = val;
3249
3210
  }
3250
3211
  };
3251
3212
  var LookupInfo = class {
3252
- constructor(name, val) {
3253
- this.name = name;
3213
+ constructor(val) {
3254
3214
  this.val = val;
3255
3215
  }
3256
3216
  };
@@ -3298,13 +3258,13 @@ var Component = class {
3298
3258
  continue;
3299
3259
  }
3300
3260
  const val = parseProvide(this._rawProvide[key], ctx);
3301
- if (val) this.provide[key] = new ProvideInfo(key, val);
3261
+ if (val) this.provide[key] = new ProvideInfo(val);
3302
3262
  }
3303
3263
  for (const entry of this._rawLookup) {
3304
3264
  const name = isString(entry) ? entry : isString(entry?.name) ? entry.name : null;
3305
3265
  if (name === null) continue;
3306
3266
  const defStr = isString(entry?.default) ? entry.default : null;
3307
- this.lookup[name] = new LookupInfo(name, defStr === null ? null : parseField(defStr, ctx));
3267
+ this.lookup[name] = new LookupInfo(defStr === null ? null : parseField(defStr, ctx));
3308
3268
  }
3309
3269
  for (const key in this.lookup)
3310
3270
  if (this.provide[key] !== void 0)
@@ -3334,7 +3294,7 @@ var Component = class {
3334
3294
  // src/stack.js
3335
3295
  var STOP = /* @__PURE__ */ Symbol("STOP");
3336
3296
  var NEXT = /* @__PURE__ */ Symbol("NEXT");
3337
- var DEFAULT_LOOKUP_ROUTE = ["dyn", "lex"];
3297
+ var DEFAULT_ROUTE = ["dyn", "lex"];
3338
3298
  function routeLookup(route, lex, dyn) {
3339
3299
  for (let i = 0; i < route.length; i++) {
3340
3300
  const leg = route[i];
@@ -3456,20 +3416,6 @@ var Stack = class _Stack {
3456
3416
  lookupBind(name) {
3457
3417
  return lookup(this.binds, name);
3458
3418
  }
3459
- // The `lex` leg: what a name means in the registration scope of the component being
3460
- // rendered. The scope chain holds components, so this leg only ever answers for a
3461
- // type name — for a value name it is a miss, which is why one default route serves
3462
- // both. Guarded: a non-component `it` has no scope to ask.
3463
- _lookupLex(name) {
3464
- return this.comps.getCompFor(this.it)?.scope.lookupComponent(name) ?? null;
3465
- }
3466
- lookupRouted(name, route = DEFAULT_LOOKUP_ROUTE) {
3467
- return routeLookup(
3468
- route,
3469
- () => this._lookupLex(name),
3470
- () => this.lookupDynamic(name)
3471
- );
3472
- }
3473
3419
  lookupFieldRaw(name) {
3474
3420
  return this.it[name] ?? null;
3475
3421
  }
@@ -3502,34 +3448,16 @@ var Stack = class _Stack {
3502
3448
  // src/oo.js
3503
3449
  var BAD_VALUE = /* @__PURE__ */ Symbol("BadValue");
3504
3450
  var nullCoercer = (v) => v;
3505
- function defaultToData(v) {
3506
- if (v instanceof Map) return [...v.entries()];
3507
- if (v instanceof Set) return [...v.values()];
3508
- return v;
3509
- }
3510
3451
  var Field = class {
3511
3452
  constructor(type, name, typeCheck, coercer, defaultValue = null) {
3512
3453
  this.type = type;
3513
3454
  this.name = name;
3514
3455
  this.typeCheck = typeCheck;
3515
3456
  this.coercer = coercer;
3516
- this.checks = [];
3517
3457
  this.defaultValue = defaultValue;
3518
3458
  }
3519
- toDataDef() {
3520
- return { type: this.type, defaultValue: defaultToData(this.defaultValue) };
3521
- }
3522
- getFirstFailingCheck(v) {
3523
- if (!this.typeCheck.isValid(v)) return this.typeCheck;
3524
- for (const check3 of this.checks) if (!check3.isValid(v)) return check3;
3525
- return null;
3526
- }
3527
3459
  isValid(v) {
3528
- return this.getFirstFailingCheck(v) === null;
3529
- }
3530
- addCheck(check3) {
3531
- this.checks.push(check3);
3532
- return this;
3460
+ return this.typeCheck(v);
3533
3461
  }
3534
3462
  coerceOr(v, defaultValue = null) {
3535
3463
  if (this.isValid(v)) return v;
@@ -3540,135 +3468,79 @@ var Field = class {
3540
3468
  return this.coerceOr(v, this.defaultValue);
3541
3469
  }
3542
3470
  };
3543
- var Check = class {
3544
- isValid(_v) {
3545
- return true;
3546
- }
3547
- getMessage(_v) {
3548
- return "Invalid";
3549
- }
3550
- };
3551
- var CheckTypeAny = class extends Check {
3552
- };
3553
- var CHECK_TYPE_ANY = new CheckTypeAny();
3554
- var FnCheck = class extends Check {
3555
- constructor(isValidFn, getMessageFn) {
3556
- super();
3557
- this._isValid = isValidFn;
3558
- this._getMessage = getMessageFn;
3559
- }
3560
- isValid(v) {
3561
- return this._isValid(v);
3562
- }
3563
- getMessage(v) {
3564
- return this._getMessage(v);
3565
- }
3471
+ var CHECK_TYPE_ANY = (_v) => true;
3472
+ var CHECK_TYPE_INT = Number.isInteger;
3473
+ var CHECK_TYPE_FLOAT = Number.isFinite;
3474
+ var CHECK_TYPE_BOOL = (v) => typeof v === "boolean";
3475
+ var CHECK_TYPE_STRING = (v) => typeof v === "string";
3476
+ var CHECK_TYPE_LIST = Array.isArray;
3477
+ var CHECK_TYPE_OBJECT = isPlainObject;
3478
+ var CHECK_TYPE_MAP = (v) => v instanceof Map;
3479
+ var CHECK_TYPE_SET = (v) => v instanceof Set;
3480
+ var COERCE_NONE = (_v) => null;
3481
+ var COERCE_BOOL = (v) => !!v;
3482
+ var COERCE_STRING = (v) => v?.toString?.() ?? "";
3483
+ var COERCE_INT = (v) => Number.isFinite(v) ? Math.trunc(v) : null;
3484
+ var COERCE_LIST = (v) => Array.isArray(v) ? [...v] : null;
3485
+ var COERCE_OBJECT = (v) => isPlainObject(v) ? { ...v } : null;
3486
+ var COERCE_MAP = (v) => {
3487
+ if (v instanceof Map) return new Map(v);
3488
+ if (Array.isArray(v) || isPlainObject(v))
3489
+ return new Map(Array.isArray(v) ? v : Object.entries(v));
3490
+ return null;
3566
3491
  };
3567
- var check = (fn, message) => new FnCheck(fn, () => message);
3568
- var CHECK_TYPE_INT = check(Number.isInteger, "Integer expected");
3569
- var CHECK_TYPE_FLOAT = check(Number.isFinite, "Float expected");
3570
- var CHECK_TYPE_BOOL = check((v) => typeof v === "boolean", "Boolean expected");
3571
- var CHECK_TYPE_STRING = check((v) => typeof v === "string", "String expected");
3572
- var CHECK_TYPE_LIST = check(Array.isArray, "Array expected");
3573
- var CHECK_TYPE_OBJECT = check(isPlainObject, "Plain object expected");
3574
- var CHECK_TYPE_MAP = check((v) => v instanceof Map, "Map expected");
3575
- var CHECK_TYPE_SET = check((v) => v instanceof Set, "Set expected");
3492
+ var COERCE_SET = (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null;
3576
3493
  var FieldBool = class extends Field {
3577
3494
  constructor(name, defaultValue = false) {
3578
- super("bool", name, CHECK_TYPE_BOOL, (v) => !!v, defaultValue);
3495
+ super("bool", name, CHECK_TYPE_BOOL, COERCE_BOOL, defaultValue);
3579
3496
  }
3580
3497
  };
3581
3498
  var FieldAny = class extends Field {
3582
3499
  constructor(name, defaultValue = null) {
3583
3500
  super("any", name, CHECK_TYPE_ANY, nullCoercer, defaultValue);
3584
3501
  }
3585
- toDataDef() {
3586
- return { type: getTypeName(this.defaultValue) ?? "any", defaultValue: this.defaultValue };
3587
- }
3588
3502
  };
3589
3503
  var FieldString = class extends Field {
3590
3504
  constructor(name, defaultValue = "") {
3591
- super("text", name, CHECK_TYPE_STRING, (v) => v?.toString?.() ?? "", defaultValue);
3505
+ super("text", name, CHECK_TYPE_STRING, COERCE_STRING, defaultValue);
3592
3506
  }
3593
3507
  };
3594
3508
  var FieldInt = class extends Field {
3595
3509
  constructor(name, defaultValue = 0) {
3596
- super(
3597
- "int",
3598
- name,
3599
- CHECK_TYPE_INT,
3600
- (v) => Number.isFinite(v) ? Math.trunc(v) : null,
3601
- defaultValue
3602
- );
3510
+ super("int", name, CHECK_TYPE_INT, COERCE_INT, defaultValue);
3603
3511
  }
3604
3512
  };
3605
3513
  var FieldFloat = class extends Field {
3606
3514
  constructor(name, defaultValue = 0) {
3607
- super("float", name, CHECK_TYPE_FLOAT, (_) => null, defaultValue);
3608
- }
3609
- };
3610
- var getTypeName = (v) => v?.constructor?.[COMPONENT]?.name ?? v?.constructor?.getMetaClass?.()?.name ?? null;
3611
- var CheckTypeName = class {
3612
- constructor(typeName) {
3613
- this.typeName = typeName;
3614
- }
3615
- isValid(v) {
3616
- return getTypeName(v) === this.typeName;
3617
- }
3618
- getMessage(v) {
3619
- return `Expected "${this.typeName}", got "${getTypeName(v)}"`;
3515
+ super("float", name, CHECK_TYPE_FLOAT, COERCE_NONE, defaultValue);
3620
3516
  }
3621
3517
  };
3518
+ var metaOf = (v) => v?.constructor?.[COMPONENT] ?? v?.constructor?.getMetaClass?.();
3519
+ var getTypeName = (v) => metaOf(v)?.name ?? null;
3622
3520
  var FieldComp = class extends Field {
3623
3521
  constructor(type, name, args) {
3624
- super(type, name, new CheckTypeName(type), nullCoercer, null);
3522
+ super(type, name, (v) => getTypeName(v) === type, nullCoercer, null);
3625
3523
  this.args = args;
3626
3524
  }
3627
- toDataDef() {
3628
- return { component: this.type, args: this.args };
3629
- }
3630
3525
  };
3631
3526
  var FieldList = class extends Field {
3632
3527
  constructor(name, defaultValue = []) {
3633
- super("list", name, CHECK_TYPE_LIST, (v) => Array.isArray(v) ? [...v] : null, defaultValue);
3528
+ super("list", name, CHECK_TYPE_LIST, COERCE_LIST, defaultValue);
3634
3529
  }
3635
3530
  };
3636
3531
  var FieldObject = class extends Field {
3637
3532
  constructor(name, defaultValue = {}) {
3638
- super(
3639
- "object",
3640
- name,
3641
- CHECK_TYPE_OBJECT,
3642
- (v) => isPlainObject(v) ? { ...v } : null,
3643
- defaultValue
3644
- );
3533
+ super("object", name, CHECK_TYPE_OBJECT, COERCE_OBJECT, defaultValue);
3645
3534
  }
3646
3535
  };
3647
3536
  var FieldMap = class extends Field {
3648
3537
  constructor(name, defaultValue = /* @__PURE__ */ new Map()) {
3649
- super(
3650
- "map",
3651
- name,
3652
- CHECK_TYPE_MAP,
3653
- (v) => {
3654
- if (v instanceof Map) return new Map(v);
3655
- if (Array.isArray(v) || isPlainObject(v))
3656
- return new Map(Array.isArray(v) ? v : Object.entries(v));
3657
- return null;
3658
- },
3659
- defaultValue
3660
- );
3538
+ super("map", name, CHECK_TYPE_MAP, COERCE_MAP, defaultValue);
3661
3539
  }
3662
3540
  };
3663
3541
  var FieldSet = class extends Field {
3664
3542
  constructor(name, defaultValue = /* @__PURE__ */ new Set()) {
3665
- super(
3666
- "set",
3667
- name,
3668
- CHECK_TYPE_SET,
3669
- (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null,
3670
- defaultValue
3671
- );
3543
+ super("set", name, CHECK_TYPE_SET, COERCE_SET, defaultValue);
3672
3544
  }
3673
3545
  };
3674
3546
  function mkCompField(field, scope, args) {
@@ -3766,8 +3638,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
3766
3638
  const value = fields[field];
3767
3639
  const type = typeof value;
3768
3640
  if (type === "string") b.addField(field, value, FieldString);
3769
- else if (type === "number")
3770
- b.addField(field, value, Number.isInteger(value) ? FieldInt : FieldFloat);
3641
+ else if (type === "number") b.addField(field, value, FieldFloat);
3771
3642
  else if (type === "boolean") b.addField(field, value, FieldBool);
3772
3643
  else if (Array.isArray(value)) b.addField(field, [...value], FieldList);
3773
3644
  else if (value instanceof Set) b.addField(field, new Set(value), FieldSet);
@@ -3788,7 +3659,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
3788
3659
  return b.build();
3789
3660
  }
3790
3661
  function validateDraftFields(current2, draft) {
3791
- const meta = current2?.constructor?.[COMPONENT] ?? current2?.constructor?.getMetaClass?.();
3662
+ const meta = metaOf(current2);
3792
3663
  if (!meta) return;
3793
3664
  for (const [name, field] of Object.entries(meta.fields)) {
3794
3665
  const value = draft[name];
@@ -3915,28 +3786,46 @@ var Transactor = class {
3915
3786
  if (i !== -1) this._refusalObservers.splice(i, 1);
3916
3787
  };
3917
3788
  }
3918
- // Build and dispatch the observer record for a settled transaction. The
3919
- // resolved handler (`_resolvedHandler`/`_matched`) and per-leaf before/after
3920
- // (`_before`/`_after`) were captured while the handler ran (see callHandler /
3921
- // Transaction.run). No-op when nobody is observing.
3789
+ // Build and dispatch one observer record. Pins field-resolved keys (e.g. a
3790
+ // `.a[.selId]` render target reconstructed from a DOM event) against the root the
3791
+ // handler read, so pathKeys carries concrete keys instead of dropping the dynamic
3792
+ // step. No-op when nobody is observing.
3793
+ _emitRecord(root, { kind, name, args, path, targetPath, handler, handlerName, matched, before, after, parent }) {
3794
+ if (this._observers.length === 0) return;
3795
+ const pinned = path.pinKeys(root);
3796
+ this._emit({
3797
+ kind,
3798
+ name,
3799
+ args: args ?? null,
3800
+ path: pinned,
3801
+ pathKeys: pinned.toKeys(),
3802
+ targetPath,
3803
+ handler: handler ?? null,
3804
+ handlerName: handlerName ?? (handler?.name || null),
3805
+ matched: matched ?? null,
3806
+ before,
3807
+ after,
3808
+ parent,
3809
+ timestamp: Date.now()
3810
+ });
3811
+ }
3812
+ // The observer record for a settled transaction. The resolved handler
3813
+ // (`_resolvedHandler`/`_matched`) and per-leaf before/after (`_before`/`_after`)
3814
+ // were captured while the handler ran (see callHandler / Transaction.run).
3922
3815
  _emitTransaction(transaction, root) {
3923
3816
  if (this._observers.length === 0) return;
3924
3817
  if (transaction._resolvedHandler === void 0) return;
3925
- const path = transaction.getTransactionPath().pinKeys(root);
3926
- this._emit({
3818
+ this._emitRecord(root, {
3927
3819
  kind: transaction.observeKind,
3928
3820
  name: transaction.observeName,
3929
- args: transaction.args ?? null,
3930
- path,
3931
- pathKeys: path.toKeys(),
3821
+ args: transaction.args,
3822
+ path: transaction.getTransactionPath(),
3932
3823
  targetPath: transaction.targetPath ?? transaction.path,
3933
- handler: transaction._resolvedHandler ?? null,
3934
- handlerName: transaction._resolvedHandler?.name || null,
3935
- matched: transaction._matched ?? null,
3824
+ handler: transaction._resolvedHandler,
3825
+ matched: transaction._matched,
3936
3826
  before: transaction._before,
3937
3827
  after: transaction._after,
3938
- parent: transaction.parentTransaction,
3939
- timestamp: Date.now()
3828
+ parent: transaction.parentTransaction
3940
3829
  });
3941
3830
  }
3942
3831
  // Make `child` a tracked unit of `parent`'s subtree: the parent's completion stays open
@@ -4034,7 +3923,7 @@ var Transaction = class {
4034
3923
  // rather than throwing, so a stray call from the wrong place is a message and not a
4035
3924
  // crash. `walk` is undefined here, which is how ctx.reply/ctx.fail tell the two apart.
4036
3925
  stop() {
4037
- console.warn('ctx.stop() is only meaningful in an "intent" handler - ignored');
3926
+ warnNotIntent("stop");
4038
3927
  }
4039
3928
  forward(_opts) {
4040
3929
  console.warn('ctx.forward() needs a "receive" or "intent" handler - ignored');
@@ -4119,11 +4008,8 @@ var InputEvent = class extends Transaction {
4119
4008
  }
4120
4009
  this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
4121
4010
  }
4122
- buildStack(root, comps) {
4123
- return this.path.toTransactionPath().buildStack(Stack.root(comps, root, this));
4124
- }
4125
4011
  getHandlerAndArgs(root, _instance, comps) {
4126
- const stack = this.buildStack(root, comps);
4012
+ const stack = this.path.toTransactionPath().buildStack(Stack.root(comps, root, this));
4127
4013
  const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
4128
4014
  this._handlerArgs = [...args];
4129
4015
  const path = this.dispatchPath;
@@ -4225,7 +4111,6 @@ var IntentEvent = class extends NameArgsTransaction {
4225
4111
  };
4226
4112
  var PASS = /* @__PURE__ */ Symbol.for("tutuca.intent.pass");
4227
4113
  var REFUSAL_RING_CAP = 200;
4228
- var DEFAULT_ROUTE = ["dyn", "lex"];
4229
4114
  var INTENT_DEPTH = 64;
4230
4115
  var IntentWalk = class {
4231
4116
  constructor(transactor, path, name, args, opts, parent, release) {
@@ -4274,24 +4159,19 @@ var IntentWalk = class {
4274
4159
  const txnPath = this.origin.toTransactionPath();
4275
4160
  const leaf = txnPath.lookup(root);
4276
4161
  const chain = this.transactor.comps.getIntentChainFor(leaf, this.name);
4277
- if (this.transactor._observers.length > 0) {
4278
- const path = txnPath.pinKeys(root);
4279
- this.transactor._emit({
4280
- kind: "intent",
4281
- name: this.name,
4282
- args: this.args,
4283
- path,
4284
- pathKeys: path.toKeys(),
4285
- targetPath: this.origin,
4286
- handler: chain[0]?.fn ?? null,
4287
- handlerName: chain[0]?.fn?.name || this.name,
4288
- matched: chain.length > 0 ? "exact" : "none",
4289
- before: leaf,
4290
- after: void 0,
4291
- parent: this.parent,
4292
- timestamp: Date.now()
4293
- });
4294
- }
4162
+ this.transactor._emitRecord(root, {
4163
+ kind: "intent",
4164
+ name: this.name,
4165
+ args: this.args,
4166
+ path: txnPath,
4167
+ targetPath: this.origin,
4168
+ handler: chain[0],
4169
+ handlerName: chain[0]?.name || this.name,
4170
+ matched: chain.length > 0 ? "exact" : "none",
4171
+ before: leaf,
4172
+ after: void 0,
4173
+ parent: this.parent
4174
+ });
4295
4175
  if (chain.length === 0) return this.advance();
4296
4176
  const p = this._runLex(chain, 0);
4297
4177
  this.transactor._inflight.add(p);
@@ -4302,7 +4182,7 @@ var IntentWalk = class {
4302
4182
  if (i >= chain.length) return this.advance();
4303
4183
  const ctx = new Dispatcher(this.origin, this.transactor, this.parent);
4304
4184
  try {
4305
- const res = await chain[i].fn.apply(null, [...this.args, ctx]);
4185
+ const res = await chain[i].apply(null, [...this.args, ctx]);
4306
4186
  if (res === PASS) return this._runLex(chain, i + 1);
4307
4187
  this.answer("Ok", res);
4308
4188
  } catch (error) {
@@ -4455,9 +4335,8 @@ var Dispatcher = class {
4455
4335
  // the same spelling as `ctx.intent` — `["dyn"]` the render ancestry, `["lex"]` the
4456
4336
  // registration scope, default both.
4457
4337
  lookup(name, opts) {
4458
- const route = opts?.route ?? DEFAULT_LOOKUP_ROUTE;
4459
4338
  return routeLookup(
4460
- route,
4339
+ opts?.route ?? DEFAULT_ROUTE,
4461
4340
  () => this._lookupLex(name),
4462
4341
  () => this._stack()?.lookupDynamic(name) ?? null
4463
4342
  );
@@ -4476,12 +4355,10 @@ var Dispatcher = class {
4476
4355
  // can only ever answer with one; the `dyn` leg reads a binding an ancestor
4477
4356
  // published, so it is the leg that has to be checked.
4478
4357
  lookupType(name, opts) {
4479
- const v = this.lookup(name, opts);
4358
+ const route = opts?.route ?? DEFAULT_ROUTE;
4359
+ const v = this.lookup(name, { route });
4480
4360
  if (v == null) {
4481
- this.transactor.refuse("TYPE_NOT_FOUND", {
4482
- name,
4483
- route: opts?.route ?? DEFAULT_LOOKUP_ROUTE
4484
- });
4361
+ this.transactor.refuse("TYPE_NOT_FOUND", { name, route });
4485
4362
  return null;
4486
4363
  }
4487
4364
  if (v?.[COMPONENT] == null) {
@@ -4606,7 +4483,14 @@ var App = class {
4606
4483
  const { type } = e;
4607
4484
  const isDrag = type === "dragover" || type === "dragstart" || type === "dragend" || type === "drop";
4608
4485
  const { rootNode: root, maxEventNodeDepth: maxDepth, comps, transactor } = this;
4609
- const [path, handlers] = Path.fromEvent(e, root, maxDepth, comps, !isDrag);
4486
+ const [path, handlers] = Path.fromNodeAndEventName(
4487
+ e.target,
4488
+ type,
4489
+ root,
4490
+ maxDepth,
4491
+ comps,
4492
+ !isDrag
4493
+ );
4610
4494
  if (isDrag) this._handleDragEvent(e, type, path);
4611
4495
  if (path !== null && handlers !== null)
4612
4496
  for (const handler of handlers) transactor.transactInputNow(path, e, handler, this.dragInfo);
@@ -4668,7 +4552,7 @@ var App = class {
4668
4552
  const value = txnPath.lookup(rootValue);
4669
4553
  const dragType = e.target.dataset.dragtype ?? "?";
4670
4554
  const stack = path.toTransactionPath().buildStack(this.makeStack(rootValue));
4671
- this.dragInfo = new DragInfo(txnPath, stack, e, value, dragType, e.target);
4555
+ this.dragInfo = new DragInfo(stack, value, dragType, e.target);
4672
4556
  } else if (type === "drop") {
4673
4557
  e.preventDefault();
4674
4558
  this._cleanDragOverAttrs();
@@ -4805,10 +4689,8 @@ function getClosestDropTarget(target, rootNode, count) {
4805
4689
  return null;
4806
4690
  }
4807
4691
  var DragInfo = class {
4808
- constructor(path, stack, e, val, type, node) {
4809
- this.path = path;
4692
+ constructor(stack, val, type, node) {
4810
4693
  this.stack = stack;
4811
- this.e = e;
4812
4694
  this.val = val;
4813
4695
  this.type = type;
4814
4696
  this.node = node;
@@ -4900,6 +4782,8 @@ var Renderer = class {
4900
4782
  setNullCache() {
4901
4783
  this.cache = new NullDomCache();
4902
4784
  }
4785
+ // Library utilities for consumers embedding tutuca: render a value to a detached
4786
+ // DOM node / an HTML string. Not called by the framework itself.
4903
4787
  renderToDOM(stack, val) {
4904
4788
  const rootNode = document.createElement("div");
4905
4789
  const rOpts = { document };
@@ -5024,7 +4908,7 @@ function dispatchPhase(dispatcher, targetPath, phase, self) {
5024
4908
  var css = String.raw;
5025
4909
  var html = String.raw;
5026
4910
  var macro = (defaults, rawView) => new Macro(defaults, rawView);
5027
- function check2(_app) {
4911
+ function check(_app) {
5028
4912
  return { error: 0, warn: 0, hint: 0, dummyCheck: true };
5029
4913
  }
5030
4914
  async function test(_opts) {
@@ -5048,7 +4932,7 @@ export {
5048
4932
  PASS,
5049
4933
  ParseContext,
5050
4934
  SEQ_INFO,
5051
- check2 as check,
4935
+ check,
5052
4936
  collectIterBindings,
5053
4937
  component,
5054
4938
  css,