tutuca 0.11.2 → 0.12.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.
Files changed (115) hide show
  1. package/dist/tutuca-cli.js +130 -104
  2. package/dist/tutuca-dev.ext.js +121 -90
  3. package/dist/tutuca-dev.js +121 -90
  4. package/dist/tutuca-dev.min.js +3 -3
  5. package/dist/tutuca-extra.ext.js +116 -59
  6. package/dist/tutuca-extra.js +116 -59
  7. package/dist/tutuca-extra.min.js +2 -2
  8. package/dist/tutuca-storybook.js +3 -3
  9. package/dist/tutuca.ext.js +116 -59
  10. package/dist/tutuca.js +116 -59
  11. package/dist/tutuca.min.js +2 -2
  12. package/package.json +1 -1
  13. package/skill/margaui/SKILL.md +105 -0
  14. package/skill/margaui/components/accordion.md +127 -0
  15. package/skill/margaui/components/alert.md +174 -0
  16. package/skill/margaui/components/aura.md +97 -0
  17. package/skill/margaui/components/avatar.md +220 -0
  18. package/skill/margaui/components/badge.md +193 -0
  19. package/skill/margaui/components/breadcrumbs.md +103 -0
  20. package/skill/margaui/components/button.md +322 -0
  21. package/skill/margaui/components/calendar.md +67 -0
  22. package/skill/margaui/components/card.md +373 -0
  23. package/skill/margaui/components/carousel.md +387 -0
  24. package/skill/margaui/components/chat.md +171 -0
  25. package/skill/margaui/components/checkbox.md +101 -0
  26. package/skill/margaui/components/collapse.md +172 -0
  27. package/skill/margaui/components/countdown.md +165 -0
  28. package/skill/margaui/components/diff.md +53 -0
  29. package/skill/margaui/components/divider.md +107 -0
  30. package/skill/margaui/components/dock.md +173 -0
  31. package/skill/margaui/components/drawer.md +184 -0
  32. package/skill/margaui/components/dropdown.md +388 -0
  33. package/skill/margaui/components/fab.md +346 -0
  34. package/skill/margaui/components/fieldset.md +88 -0
  35. package/skill/margaui/components/file-input.md +84 -0
  36. package/skill/margaui/components/filter.md +52 -0
  37. package/skill/margaui/components/footer.md +583 -0
  38. package/skill/margaui/components/hero.md +135 -0
  39. package/skill/margaui/components/hover-3d.md +129 -0
  40. package/skill/margaui/components/hover-gallery.md +49 -0
  41. package/skill/margaui/components/indicator.md +265 -0
  42. package/skill/margaui/components/input.md +389 -0
  43. package/skill/margaui/components/join.md +100 -0
  44. package/skill/margaui/components/kbd.md +127 -0
  45. package/skill/margaui/components/label.md +102 -0
  46. package/skill/margaui/components/link.md +96 -0
  47. package/skill/margaui/components/list.md +182 -0
  48. package/skill/margaui/components/loading.md +105 -0
  49. package/skill/margaui/components/mask.md +168 -0
  50. package/skill/margaui/components/megamenu.md +131 -0
  51. package/skill/margaui/components/menu.md +887 -0
  52. package/skill/margaui/components/mockup-browser.md +39 -0
  53. package/skill/margaui/components/mockup-code.md +81 -0
  54. package/skill/margaui/components/mockup-phone.md +39 -0
  55. package/skill/margaui/components/mockup-window.md +33 -0
  56. package/skill/margaui/components/modal.md +196 -0
  57. package/skill/margaui/components/navbar.md +282 -0
  58. package/skill/margaui/components/otp.md +171 -0
  59. package/skill/margaui/components/pagination.md +122 -0
  60. package/skill/margaui/components/progress.md +135 -0
  61. package/skill/margaui/components/radial-progress.md +67 -0
  62. package/skill/margaui/components/radio.md +133 -0
  63. package/skill/margaui/components/range.md +134 -0
  64. package/skill/margaui/components/rating.md +170 -0
  65. package/skill/margaui/components/select.md +225 -0
  66. package/skill/margaui/components/skeleton.md +64 -0
  67. package/skill/margaui/components/stack.md +142 -0
  68. package/skill/margaui/components/stat.md +254 -0
  69. package/skill/margaui/components/status.md +73 -0
  70. package/skill/margaui/components/steps.md +138 -0
  71. package/skill/margaui/components/swap.md +152 -0
  72. package/skill/margaui/components/tab.md +248 -0
  73. package/skill/margaui/components/table.md +1018 -0
  74. package/skill/margaui/components/text-rotate.md +91 -0
  75. package/skill/margaui/components/textarea.md +85 -0
  76. package/skill/margaui/components/theme-controller.md +266 -0
  77. package/skill/margaui/components/timeline.md +1356 -0
  78. package/skill/margaui/components/toast.md +165 -0
  79. package/skill/margaui/components/toggle.md +135 -0
  80. package/skill/margaui/components/tooltip.md +181 -0
  81. package/skill/margaui/components/validator.md +163 -0
  82. package/skill/tutuca/SKILL.md +56 -0
  83. package/skill/tutuca/advanced.md +212 -0
  84. package/skill/tutuca/cli.md +239 -0
  85. package/skill/tutuca/component-design.md +168 -0
  86. package/skill/tutuca/core.md +918 -0
  87. package/skill/tutuca/iteration.md +207 -0
  88. package/skill/tutuca/macros.md +86 -0
  89. package/skill/tutuca/margaui.md +175 -0
  90. package/skill/tutuca/messages-and-intents.md +399 -0
  91. package/skill/tutuca/patterns/README.md +48 -0
  92. package/skill/tutuca/patterns/add-a-story.md +26 -0
  93. package/skill/tutuca/patterns/bind-text-and-attributes.md +30 -0
  94. package/skill/tutuca/patterns/conditional-attribute-value.md +29 -0
  95. package/skill/tutuca/patterns/coordinate-components.md +54 -0
  96. package/skill/tutuca/patterns/edit-through-a-dynamic-target.md +27 -0
  97. package/skill/tutuca/patterns/enrich-each-item.md +25 -0
  98. package/skill/tutuca/patterns/file-input.md +39 -0
  99. package/skill/tutuca/patterns/filter-a-list.md +25 -0
  100. package/skill/tutuca/patterns/filter-and-paginate.md +60 -0
  101. package/skill/tutuca/patterns/handle-events.md +44 -0
  102. package/skill/tutuca/patterns/iterate-a-list.md +18 -0
  103. package/skill/tutuca/patterns/paginate-a-list.md +29 -0
  104. package/skill/tutuca/patterns/render-a-child-component.md +21 -0
  105. package/skill/tutuca/patterns/reuse-markup-with-macros.md +36 -0
  106. package/skill/tutuca/patterns/share-state-across-the-tree.md +38 -0
  107. package/skill/tutuca/patterns/show-or-hide-content.md +23 -0
  108. package/skill/tutuca/patterns/switch-between-views.md +30 -0
  109. package/skill/tutuca/patterns/tabbed-interface.md +43 -0
  110. package/skill/tutuca/semantics.md +195 -0
  111. package/skill/tutuca/storybook.md +270 -0
  112. package/skill/tutuca/styles.md +48 -0
  113. package/skill/tutuca/testing.md +345 -0
  114. package/skill/tutuca-source/SKILL.md +33 -0
  115. package/skill/tutuca-source/tutuca.ext.js +4301 -0
@@ -566,6 +566,9 @@ var PathBuilder = class {
566
566
  }
567
567
  };
568
568
 
569
+ // src/util/env.js
570
+ var isMac = (globalThis.navigator?.userAgent ?? "").toLowerCase().includes("mac");
571
+
569
572
  // src/value.js
570
573
  var VALID_VAL_ID_RE = /^[a-zA-Z][a-zA-Z0-9_]*\??$/;
571
574
  var isValidValId = (name) => VALID_VAL_ID_RE.test(name);
@@ -584,6 +587,7 @@ var K_NAME = 32;
584
587
  var K_TYPE = 64;
585
588
  var K_SEQ = 256;
586
589
  var K_METHOD = 1024;
590
+ var K_EVENT = 2048;
587
591
  var G_BOOL = K_FIELD | K_METHOD | K_BIND | K_DYN | K_CONST;
588
592
  var G_TEXT = G_BOOL | K_STRTPL;
589
593
  var G_COMPONENT = K_FIELD | K_SEQ | K_DYN;
@@ -591,6 +595,7 @@ var G_SEQUENCE = K_FIELD | K_DYN;
591
595
  var G_PROVIDE = K_FIELD | K_SEQ;
592
596
  var G_FIELD = K_FIELD | K_METHOD | K_CONST | K_SEQ;
593
597
  var G_VALUE = K_FIELD | K_METHOD | K_BIND | K_DYN | K_NAME | K_TYPE | K_CONST;
598
+ var G_HANDLER_ARG = G_VALUE & ~K_NAME | K_EVENT;
594
599
  var G_ALL = G_VALUE | K_STRTPL | K_SEQ;
595
600
  function sizeOf(v) {
596
601
  if (v == null) return null;
@@ -600,6 +605,10 @@ function sizeOf(v) {
600
605
  if (typeof l === "number") return l;
601
606
  return isPlainObject(v) ? Object.keys(v).length : null;
602
607
  }
608
+ var toNullIfNaN = (v) => Number.isNaN(v) ? null : v;
609
+ function getValue(e) {
610
+ return e.target.type === "checkbox" ? e.target.checked : (e instanceof CustomEvent ? e.detail : e.target.value) ?? null;
611
+ }
603
612
  var predTruthy = (v) => {
604
613
  const n = sizeOf(v);
605
614
  return n === null ? !!v : n > 0;
@@ -650,6 +659,10 @@ function parseToken(s, px) {
650
659
  const num = VALID_FLOAT_RE.test(s) ? parseFloat(s) : null;
651
660
  if (Number.isFinite(num)) return new ConstVal(num);
652
661
  if (s === "true" || s === "false") return new ConstVal(s === "true");
662
+ if (c0 === 101) {
663
+ const m = /^e(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.exec(s);
664
+ if (m !== null) return new EventMemberVal(s.split(".").slice(1));
665
+ }
653
666
  if (c0 >= 97 && c0 <= 122) return mkVal(s, NameVal);
654
667
  if (c0 >= 65 && c0 <= 90) return mkVal(s, TypeVal);
655
668
  return null;
@@ -725,7 +738,7 @@ function _parseHandler(s, px, namespace, allowArgs, report, allowMethod) {
725
738
  const args = new Array(tokens.length - 1);
726
739
  for (let i = 1; i < tokens.length; i++) {
727
740
  const val = parseToken(tokens[i], px);
728
- if (val !== null && kindOf(val) & G_VALUE) args[i - 1] = val;
741
+ if (val !== null && kindOf(val) & G_HANDLER_ARG) args[i - 1] = val;
729
742
  else {
730
743
  if (report) px.onParseIssue("bad-value", { role: "handler-arg", value: tokens[i] });
731
744
  args[i - 1] = NULL_CONST_VAL;
@@ -768,6 +781,7 @@ function kindOf(val) {
768
781
  if (val instanceof DynVal) return K_DYN;
769
782
  if (val instanceof TypeVal) return K_TYPE;
770
783
  if (val instanceof NameVal) return K_NAME;
784
+ if (val instanceof EventMemberVal) return K_EVENT;
771
785
  return 0;
772
786
  }
773
787
  var BaseVal = class {
@@ -892,11 +906,14 @@ var HandlerNameVal = class extends NameVal {
892
906
  this.namespace = namespace;
893
907
  }
894
908
  eval(stack) {
895
- return stack.getHandlerFor(this.name, this.namespace) ?? mk404Handler(this.namespace, this.name);
909
+ return stack.getHandlerFor(this.name, this.namespace) ?? mk404Handler(stack, this.namespace, this.name);
896
910
  }
897
911
  };
898
- var mk404Handler = (type, name) => function(...args) {
899
- console.warn("handler not found", { type, name, args }, this);
912
+ var mk404Handler = (stack, type, name) => function(...args) {
913
+ const transactor = stack?.ctx?.transactor;
914
+ if (transactor)
915
+ transactor.refuse("NO_HANDLER", { namespace: type, name, argCount: args.length });
916
+ else console.warn("handler not found", { type, name });
900
917
  return this;
901
918
  };
902
919
  var TypeVal = class extends NameVal {
@@ -904,6 +921,53 @@ var TypeVal = class extends NameVal {
904
921
  return stack.lookupType(this.name);
905
922
  }
906
923
  };
924
+ var keyIs = (k) => (e) => e.key === k;
925
+ var macCtrl = (e) => isMac && e.metaKey || e.ctrlKey;
926
+ var nullSafe = (fn) => (e, stack) => {
927
+ const info = stack.lookupDragInfo();
928
+ return info == null ? null : fn(info);
929
+ };
930
+ var EVENT_CONVENIENCES = {
931
+ value: (e) => getValue(e),
932
+ valueAsInt: (e) => toNullIfNaN(parseInt(getValue(e), 10)),
933
+ valueAsFloat: (e) => toNullIfNaN(parseFloat(getValue(e))),
934
+ isAlt: (e) => e.altKey,
935
+ isShift: (e) => e.shiftKey,
936
+ isCtrl: macCtrl,
937
+ isCmd: macCtrl,
938
+ isUpKey: keyIs("ArrowUp"),
939
+ isDownKey: keyIs("ArrowDown"),
940
+ isSend: keyIs("Enter"),
941
+ isCancel: keyIs("Escape"),
942
+ isTabKey: keyIs("Tab"),
943
+ dragInfo: (_e, stack) => stack.lookupDragInfo(),
944
+ dragType: nullSafe((info) => info.type),
945
+ dragValue: nullSafe((info) => info.val),
946
+ dragKey: nullSafe((info) => info.lookupBind("key"))
947
+ };
948
+ var EventMemberVal = class extends BaseVal {
949
+ constructor(members) {
950
+ super();
951
+ this.members = members;
952
+ }
953
+ eval(stack) {
954
+ const e = stack.lookupEvent();
955
+ if (e == null) return null;
956
+ if (this.members.length === 1) {
957
+ const convenience = EVENT_CONVENIENCES[this.members[0]];
958
+ if (convenience !== void 0) return convenience(e, stack);
959
+ }
960
+ let v = e;
961
+ for (const member of this.members) {
962
+ if (v == null) return null;
963
+ v = v[member];
964
+ }
965
+ return v ?? null;
966
+ }
967
+ toString() {
968
+ return `e.${this.members.join(".")}`;
969
+ }
970
+ };
907
971
  var RenderVal = class extends BaseVal {
908
972
  render(stack, _rx) {
909
973
  return this.eval(stack);
@@ -1835,9 +1899,6 @@ var unkIter = () => {
1835
1899
  };
1836
1900
  var SEQ_INFO = /* @__PURE__ */ Symbol.for("tutuca.seqInfo");
1837
1901
 
1838
- // src/util/env.js
1839
- var isMac = (globalThis.navigator?.userAgent ?? "").toLowerCase().includes("mac");
1840
-
1841
1902
  // src/anode.js
1842
1903
  function resolveDynProducer(comp, name) {
1843
1904
  let producerComp, producerProvide;
@@ -2884,8 +2945,19 @@ var Stack = class _Stack {
2884
2945
  const fn = this.it[name];
2885
2946
  return fn instanceof Function ? fn.call(this.it) : null;
2886
2947
  }
2887
- lookupName(name) {
2888
- return this.ctx.lookupName(name);
2948
+ // Bare implicit event names are gone: a sigil-less word cannot reach a
2949
+ // handler-arg slot anymore, so this only ever serves stale NameVals parsed
2950
+ // before the removal (e.g. macro-attr pass-throughs). Always null.
2951
+ lookupName(_name) {
2952
+ return null;
2953
+ }
2954
+ // The dispatched DOM event / drag info, read only by EventMemberVal's
2955
+ // `e.<member>` handler args. Null outside a live event transaction.
2956
+ lookupEvent() {
2957
+ return this.ctx?.event ?? null;
2958
+ }
2959
+ lookupDragInfo() {
2960
+ return this.ctx?.dragInfo ?? null;
2889
2961
  }
2890
2962
  getHandlerFor(name, key) {
2891
2963
  return this.comps.getHandlerFor(this.it, name, key);
@@ -3263,6 +3335,8 @@ var Transactor = class {
3263
3335
  this.onTransactionPushed = () => {
3264
3336
  };
3265
3337
  this._observers = [];
3338
+ this.refusals = [];
3339
+ this._refusalObservers = [];
3266
3340
  this._inflight = /* @__PURE__ */ new Set();
3267
3341
  }
3268
3342
  pushTransaction(t) {
@@ -3286,6 +3360,29 @@ var Transactor = class {
3286
3360
  _emit(record) {
3287
3361
  for (const cb of this._observers) cb(record);
3288
3362
  }
3363
+ // Record a refusal: a dispatch the runtime could not carry out. Kinds are
3364
+ // open strings; today the runtime raises NO_HANDLER (a receive name with no
3365
+ // implementation, including the auto-generated fallback firing at dispatch
3366
+ // time) and FORWARD_NO_NAME (ctx.forward() from a handler whose view wrote
3367
+ // no name). Records carry { kind, info, timestamp } and are observational —
3368
+ // the dispatch itself has already failed gracefully.
3369
+ refuse(kind, info = {}) {
3370
+ const record = { kind, info, timestamp: Date.now() };
3371
+ this.refusals.push(record);
3372
+ if (this.refusals.length > REFUSAL_RING_CAP) this.refusals.shift();
3373
+ console.warn(`tutuca refusal [${kind}]`, info);
3374
+ for (const cb of this._refusalObservers) cb(record);
3375
+ return record;
3376
+ }
3377
+ // Subscribe to refusal records as they happen. Returns an unsubscribe fn,
3378
+ // like observe().
3379
+ observeRefusals(cb) {
3380
+ this._refusalObservers.push(cb);
3381
+ return () => {
3382
+ const i = this._refusalObservers.indexOf(cb);
3383
+ if (i !== -1) this._refusalObservers.splice(i, 1);
3384
+ };
3385
+ }
3289
3386
  // Build and dispatch the observer record for a settled transaction. The
3290
3387
  // resolved handler (`_resolvedHandler`/`_matched`) and per-leaf before/after
3291
3388
  // (`_before`/`_after`) were captured while the handler ran (see callHandler /
@@ -3451,14 +3548,7 @@ var Transaction = class {
3451
3548
  this._completion?.markSelfSettled({ value: newLeaf, old: curLeaf });
3452
3549
  return curLeaf !== newLeaf ? txnPath.setValue(curRoot, newLeaf) : curRoot;
3453
3550
  }
3454
- lookupName(_name) {
3455
- return null;
3456
- }
3457
3551
  };
3458
- var toNullIfNaN = (v) => Number.isNaN(v) ? null : v;
3459
- function getValue(e) {
3460
- return e.target.type === "checkbox" ? e.target.checked : (e instanceof CustomEvent ? e.detail : e.target.value) ?? null;
3461
- }
3462
3552
  var InputEvent = class extends Transaction {
3463
3553
  constructor(path, e, handler, transactor, dragInfo) {
3464
3554
  super(path, transactor);
@@ -3496,8 +3586,10 @@ var InputEvent = class extends Transaction {
3496
3586
  const { args = this._handlerArgs ?? [], ...rest } = f;
3497
3587
  const hv = this.handler?.handlerCall?.handlerVal ?? this.handler?.handlerVal;
3498
3588
  const name = hv?.name;
3499
- if (name === void 0)
3500
- return console.warn("ctx.forward() from a handler with no name - ignored");
3589
+ if (name === void 0) {
3590
+ this.transactor.refuse("FORWARD_NO_NAME", {});
3591
+ return;
3592
+ }
3501
3593
  this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
3502
3594
  }
3503
3595
  buildRootStack(root, comps) {
@@ -3511,47 +3603,11 @@ var InputEvent = class extends Transaction {
3511
3603
  args.push(new EventContext(path, this.transactor, this));
3512
3604
  return [handler, args];
3513
3605
  }
3514
- lookupName(name) {
3515
- const { e } = this;
3516
- switch (name) {
3517
- case "value":
3518
- return getValue(e);
3519
- case "valueAsInt":
3520
- return toNullIfNaN(parseInt(getValue(e), 10));
3521
- case "valueAsFloat":
3522
- return toNullIfNaN(parseFloat(getValue(e)));
3523
- case "target":
3524
- return e.target;
3525
- case "event":
3526
- return e;
3527
- case "isAlt":
3528
- return e.altKey;
3529
- case "isShift":
3530
- return e.shiftKey;
3531
- case "isCtrl":
3532
- /* falls through */
3533
- case "isCmd":
3534
- return isMac && e.metaKey || e.ctrlKey;
3535
- case "key":
3536
- return e.key;
3537
- case "keyCode":
3538
- return e.keyCode;
3539
- case "isUpKey":
3540
- return e.key === "ArrowUp";
3541
- case "isDownKey":
3542
- return e.key === "ArrowDown";
3543
- case "isSend":
3544
- return e.key === "Enter";
3545
- case "isCancel":
3546
- return e.key === "Escape";
3547
- case "isTabKey":
3548
- return e.key === "Tab";
3549
- case "ctx":
3550
- return new EventContext(this.dispatchPath, this.transactor, this);
3551
- case "dragInfo":
3552
- return this.dragInfo;
3553
- }
3554
- return null;
3606
+ // The dispatched DOM event, read only through `e.<member>` handler args
3607
+ // (src/value.js EventMemberVal via Stack.lookupEvent). There is no bare
3608
+ // implicit-name vocabulary anymore: every arg carries a sigil.
3609
+ get event() {
3610
+ return this.e;
3555
3611
  }
3556
3612
  };
3557
3613
  var NameArgsTransaction = class extends Transaction {
@@ -3642,6 +3698,7 @@ var IntentEvent = class extends NameArgsTransaction {
3642
3698
  }
3643
3699
  };
3644
3700
  var PASS = /* @__PURE__ */ Symbol.for("tutuca.intent.pass");
3701
+ var REFUSAL_RING_CAP = 200;
3645
3702
  var DEFAULT_ROUTE = ["dyn", "lex"];
3646
3703
  var INTENT_DEPTH = 64;
3647
3704
  var IntentWalk = class {
package/dist/tutuca.js CHANGED
@@ -1269,6 +1269,9 @@ var PathBuilder = class {
1269
1269
  }
1270
1270
  };
1271
1271
 
1272
+ // src/util/env.js
1273
+ var isMac = (globalThis.navigator?.userAgent ?? "").toLowerCase().includes("mac");
1274
+
1272
1275
  // src/value.js
1273
1276
  var VALID_VAL_ID_RE = /^[a-zA-Z][a-zA-Z0-9_]*\??$/;
1274
1277
  var isValidValId = (name) => VALID_VAL_ID_RE.test(name);
@@ -1287,6 +1290,7 @@ var K_NAME = 32;
1287
1290
  var K_TYPE = 64;
1288
1291
  var K_SEQ = 256;
1289
1292
  var K_METHOD = 1024;
1293
+ var K_EVENT = 2048;
1290
1294
  var G_BOOL = K_FIELD | K_METHOD | K_BIND | K_DYN | K_CONST;
1291
1295
  var G_TEXT = G_BOOL | K_STRTPL;
1292
1296
  var G_COMPONENT = K_FIELD | K_SEQ | K_DYN;
@@ -1294,6 +1298,7 @@ var G_SEQUENCE = K_FIELD | K_DYN;
1294
1298
  var G_PROVIDE = K_FIELD | K_SEQ;
1295
1299
  var G_FIELD = K_FIELD | K_METHOD | K_CONST | K_SEQ;
1296
1300
  var G_VALUE = K_FIELD | K_METHOD | K_BIND | K_DYN | K_NAME | K_TYPE | K_CONST;
1301
+ var G_HANDLER_ARG = G_VALUE & ~K_NAME | K_EVENT;
1297
1302
  var G_ALL = G_VALUE | K_STRTPL | K_SEQ;
1298
1303
  function sizeOf(v) {
1299
1304
  if (v == null) return null;
@@ -1303,6 +1308,10 @@ function sizeOf(v) {
1303
1308
  if (typeof l === "number") return l;
1304
1309
  return isPlainObject(v) ? Object.keys(v).length : null;
1305
1310
  }
1311
+ var toNullIfNaN = (v) => Number.isNaN(v) ? null : v;
1312
+ function getValue(e) {
1313
+ return e.target.type === "checkbox" ? e.target.checked : (e instanceof CustomEvent ? e.detail : e.target.value) ?? null;
1314
+ }
1306
1315
  var predTruthy = (v) => {
1307
1316
  const n = sizeOf(v);
1308
1317
  return n === null ? !!v : n > 0;
@@ -1353,6 +1362,10 @@ function parseToken(s, px) {
1353
1362
  const num = VALID_FLOAT_RE.test(s) ? parseFloat(s) : null;
1354
1363
  if (Number.isFinite(num)) return new ConstVal(num);
1355
1364
  if (s === "true" || s === "false") return new ConstVal(s === "true");
1365
+ if (c0 === 101) {
1366
+ const m = /^e(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.exec(s);
1367
+ if (m !== null) return new EventMemberVal(s.split(".").slice(1));
1368
+ }
1356
1369
  if (c0 >= 97 && c0 <= 122) return mkVal(s, NameVal);
1357
1370
  if (c0 >= 65 && c0 <= 90) return mkVal(s, TypeVal);
1358
1371
  return null;
@@ -1428,7 +1441,7 @@ function _parseHandler(s, px, namespace, allowArgs, report, allowMethod) {
1428
1441
  const args = new Array(tokens.length - 1);
1429
1442
  for (let i = 1; i < tokens.length; i++) {
1430
1443
  const val = parseToken(tokens[i], px);
1431
- if (val !== null && kindOf(val) & G_VALUE) args[i - 1] = val;
1444
+ if (val !== null && kindOf(val) & G_HANDLER_ARG) args[i - 1] = val;
1432
1445
  else {
1433
1446
  if (report) px.onParseIssue("bad-value", { role: "handler-arg", value: tokens[i] });
1434
1447
  args[i - 1] = NULL_CONST_VAL;
@@ -1471,6 +1484,7 @@ function kindOf(val) {
1471
1484
  if (val instanceof DynVal) return K_DYN;
1472
1485
  if (val instanceof TypeVal) return K_TYPE;
1473
1486
  if (val instanceof NameVal) return K_NAME;
1487
+ if (val instanceof EventMemberVal) return K_EVENT;
1474
1488
  return 0;
1475
1489
  }
1476
1490
  var BaseVal = class {
@@ -1595,11 +1609,14 @@ var HandlerNameVal = class extends NameVal {
1595
1609
  this.namespace = namespace;
1596
1610
  }
1597
1611
  eval(stack) {
1598
- return stack.getHandlerFor(this.name, this.namespace) ?? mk404Handler(this.namespace, this.name);
1612
+ return stack.getHandlerFor(this.name, this.namespace) ?? mk404Handler(stack, this.namespace, this.name);
1599
1613
  }
1600
1614
  };
1601
- var mk404Handler = (type, name) => function(...args) {
1602
- console.warn("handler not found", { type, name, args }, this);
1615
+ var mk404Handler = (stack, type, name) => function(...args) {
1616
+ const transactor = stack?.ctx?.transactor;
1617
+ if (transactor)
1618
+ transactor.refuse("NO_HANDLER", { namespace: type, name, argCount: args.length });
1619
+ else console.warn("handler not found", { type, name });
1603
1620
  return this;
1604
1621
  };
1605
1622
  var TypeVal = class extends NameVal {
@@ -1607,6 +1624,53 @@ var TypeVal = class extends NameVal {
1607
1624
  return stack.lookupType(this.name);
1608
1625
  }
1609
1626
  };
1627
+ var keyIs = (k) => (e) => e.key === k;
1628
+ var macCtrl = (e) => isMac && e.metaKey || e.ctrlKey;
1629
+ var nullSafe = (fn) => (e, stack) => {
1630
+ const info = stack.lookupDragInfo();
1631
+ return info == null ? null : fn(info);
1632
+ };
1633
+ var EVENT_CONVENIENCES = {
1634
+ value: (e) => getValue(e),
1635
+ valueAsInt: (e) => toNullIfNaN(parseInt(getValue(e), 10)),
1636
+ valueAsFloat: (e) => toNullIfNaN(parseFloat(getValue(e))),
1637
+ isAlt: (e) => e.altKey,
1638
+ isShift: (e) => e.shiftKey,
1639
+ isCtrl: macCtrl,
1640
+ isCmd: macCtrl,
1641
+ isUpKey: keyIs("ArrowUp"),
1642
+ isDownKey: keyIs("ArrowDown"),
1643
+ isSend: keyIs("Enter"),
1644
+ isCancel: keyIs("Escape"),
1645
+ isTabKey: keyIs("Tab"),
1646
+ dragInfo: (_e, stack) => stack.lookupDragInfo(),
1647
+ dragType: nullSafe((info) => info.type),
1648
+ dragValue: nullSafe((info) => info.val),
1649
+ dragKey: nullSafe((info) => info.lookupBind("key"))
1650
+ };
1651
+ var EventMemberVal = class extends BaseVal {
1652
+ constructor(members) {
1653
+ super();
1654
+ this.members = members;
1655
+ }
1656
+ eval(stack) {
1657
+ const e = stack.lookupEvent();
1658
+ if (e == null) return null;
1659
+ if (this.members.length === 1) {
1660
+ const convenience = EVENT_CONVENIENCES[this.members[0]];
1661
+ if (convenience !== void 0) return convenience(e, stack);
1662
+ }
1663
+ let v = e;
1664
+ for (const member of this.members) {
1665
+ if (v == null) return null;
1666
+ v = v[member];
1667
+ }
1668
+ return v ?? null;
1669
+ }
1670
+ toString() {
1671
+ return `e.${this.members.join(".")}`;
1672
+ }
1673
+ };
1610
1674
  var RenderVal = class extends BaseVal {
1611
1675
  render(stack, _rx) {
1612
1676
  return this.eval(stack);
@@ -2538,9 +2602,6 @@ var unkIter = () => {
2538
2602
  };
2539
2603
  var SEQ_INFO = /* @__PURE__ */ Symbol.for("tutuca.seqInfo");
2540
2604
 
2541
- // src/util/env.js
2542
- var isMac = (globalThis.navigator?.userAgent ?? "").toLowerCase().includes("mac");
2543
-
2544
2605
  // src/anode.js
2545
2606
  function resolveDynProducer(comp, name) {
2546
2607
  let producerComp, producerProvide;
@@ -3587,8 +3648,19 @@ var Stack = class _Stack {
3587
3648
  const fn = this.it[name];
3588
3649
  return fn instanceof Function ? fn.call(this.it) : null;
3589
3650
  }
3590
- lookupName(name) {
3591
- return this.ctx.lookupName(name);
3651
+ // Bare implicit event names are gone: a sigil-less word cannot reach a
3652
+ // handler-arg slot anymore, so this only ever serves stale NameVals parsed
3653
+ // before the removal (e.g. macro-attr pass-throughs). Always null.
3654
+ lookupName(_name) {
3655
+ return null;
3656
+ }
3657
+ // The dispatched DOM event / drag info, read only by EventMemberVal's
3658
+ // `e.<member>` handler args. Null outside a live event transaction.
3659
+ lookupEvent() {
3660
+ return this.ctx?.event ?? null;
3661
+ }
3662
+ lookupDragInfo() {
3663
+ return this.ctx?.dragInfo ?? null;
3592
3664
  }
3593
3665
  getHandlerFor(name, key) {
3594
3666
  return this.comps.getHandlerFor(this.it, name, key);
@@ -3966,6 +4038,8 @@ var Transactor = class {
3966
4038
  this.onTransactionPushed = () => {
3967
4039
  };
3968
4040
  this._observers = [];
4041
+ this.refusals = [];
4042
+ this._refusalObservers = [];
3969
4043
  this._inflight = /* @__PURE__ */ new Set();
3970
4044
  }
3971
4045
  pushTransaction(t) {
@@ -3989,6 +4063,29 @@ var Transactor = class {
3989
4063
  _emit(record) {
3990
4064
  for (const cb of this._observers) cb(record);
3991
4065
  }
4066
+ // Record a refusal: a dispatch the runtime could not carry out. Kinds are
4067
+ // open strings; today the runtime raises NO_HANDLER (a receive name with no
4068
+ // implementation, including the auto-generated fallback firing at dispatch
4069
+ // time) and FORWARD_NO_NAME (ctx.forward() from a handler whose view wrote
4070
+ // no name). Records carry { kind, info, timestamp } and are observational —
4071
+ // the dispatch itself has already failed gracefully.
4072
+ refuse(kind, info = {}) {
4073
+ const record = { kind, info, timestamp: Date.now() };
4074
+ this.refusals.push(record);
4075
+ if (this.refusals.length > REFUSAL_RING_CAP) this.refusals.shift();
4076
+ console.warn(`tutuca refusal [${kind}]`, info);
4077
+ for (const cb of this._refusalObservers) cb(record);
4078
+ return record;
4079
+ }
4080
+ // Subscribe to refusal records as they happen. Returns an unsubscribe fn,
4081
+ // like observe().
4082
+ observeRefusals(cb) {
4083
+ this._refusalObservers.push(cb);
4084
+ return () => {
4085
+ const i = this._refusalObservers.indexOf(cb);
4086
+ if (i !== -1) this._refusalObservers.splice(i, 1);
4087
+ };
4088
+ }
3992
4089
  // Build and dispatch the observer record for a settled transaction. The
3993
4090
  // resolved handler (`_resolvedHandler`/`_matched`) and per-leaf before/after
3994
4091
  // (`_before`/`_after`) were captured while the handler ran (see callHandler /
@@ -4154,14 +4251,7 @@ var Transaction = class {
4154
4251
  this._completion?.markSelfSettled({ value: newLeaf, old: curLeaf });
4155
4252
  return curLeaf !== newLeaf ? txnPath.setValue(curRoot, newLeaf) : curRoot;
4156
4253
  }
4157
- lookupName(_name) {
4158
- return null;
4159
- }
4160
4254
  };
4161
- var toNullIfNaN = (v) => Number.isNaN(v) ? null : v;
4162
- function getValue(e) {
4163
- return e.target.type === "checkbox" ? e.target.checked : (e instanceof CustomEvent ? e.detail : e.target.value) ?? null;
4164
- }
4165
4255
  var InputEvent = class extends Transaction {
4166
4256
  constructor(path, e, handler, transactor, dragInfo) {
4167
4257
  super(path, transactor);
@@ -4199,8 +4289,10 @@ var InputEvent = class extends Transaction {
4199
4289
  const { args = this._handlerArgs ?? [], ...rest } = f;
4200
4290
  const hv = this.handler?.handlerCall?.handlerVal ?? this.handler?.handlerVal;
4201
4291
  const name = hv?.name;
4202
- if (name === void 0)
4203
- return console.warn("ctx.forward() from a handler with no name - ignored");
4292
+ if (name === void 0) {
4293
+ this.transactor.refuse("FORWARD_NO_NAME", {});
4294
+ return;
4295
+ }
4204
4296
  this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
4205
4297
  }
4206
4298
  buildRootStack(root, comps) {
@@ -4214,47 +4306,11 @@ var InputEvent = class extends Transaction {
4214
4306
  args.push(new EventContext(path, this.transactor, this));
4215
4307
  return [handler, args];
4216
4308
  }
4217
- lookupName(name) {
4218
- const { e } = this;
4219
- switch (name) {
4220
- case "value":
4221
- return getValue(e);
4222
- case "valueAsInt":
4223
- return toNullIfNaN(parseInt(getValue(e), 10));
4224
- case "valueAsFloat":
4225
- return toNullIfNaN(parseFloat(getValue(e)));
4226
- case "target":
4227
- return e.target;
4228
- case "event":
4229
- return e;
4230
- case "isAlt":
4231
- return e.altKey;
4232
- case "isShift":
4233
- return e.shiftKey;
4234
- case "isCtrl":
4235
- /* falls through */
4236
- case "isCmd":
4237
- return isMac && e.metaKey || e.ctrlKey;
4238
- case "key":
4239
- return e.key;
4240
- case "keyCode":
4241
- return e.keyCode;
4242
- case "isUpKey":
4243
- return e.key === "ArrowUp";
4244
- case "isDownKey":
4245
- return e.key === "ArrowDown";
4246
- case "isSend":
4247
- return e.key === "Enter";
4248
- case "isCancel":
4249
- return e.key === "Escape";
4250
- case "isTabKey":
4251
- return e.key === "Tab";
4252
- case "ctx":
4253
- return new EventContext(this.dispatchPath, this.transactor, this);
4254
- case "dragInfo":
4255
- return this.dragInfo;
4256
- }
4257
- return null;
4309
+ // The dispatched DOM event, read only through `e.<member>` handler args
4310
+ // (src/value.js EventMemberVal via Stack.lookupEvent). There is no bare
4311
+ // implicit-name vocabulary anymore: every arg carries a sigil.
4312
+ get event() {
4313
+ return this.e;
4258
4314
  }
4259
4315
  };
4260
4316
  var NameArgsTransaction = class extends Transaction {
@@ -4345,6 +4401,7 @@ var IntentEvent = class extends NameArgsTransaction {
4345
4401
  }
4346
4402
  };
4347
4403
  var PASS = /* @__PURE__ */ Symbol.for("tutuca.intent.pass");
4404
+ var REFUSAL_RING_CAP = 200;
4348
4405
  var DEFAULT_ROUTE = ["dyn", "lex"];
4349
4406
  var INTENT_DEPTH = 64;
4350
4407
  var IntentWalk = class {