tutuca 0.11.0 → 0.11.2

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 (116) hide show
  1. package/dist/tutuca-cli.js +264 -361
  2. package/dist/tutuca-components.js +175 -175
  3. package/dist/tutuca-dev.ext.js +250 -323
  4. package/dist/tutuca-dev.js +250 -323
  5. package/dist/tutuca-dev.min.js +4 -4
  6. package/dist/tutuca-extra.ext.js +55 -46
  7. package/dist/tutuca-extra.js +55 -46
  8. package/dist/tutuca-extra.min.js +3 -3
  9. package/dist/tutuca-storybook.js +29 -29
  10. package/dist/tutuca.ext.js +55 -46
  11. package/dist/tutuca.js +55 -46
  12. package/dist/tutuca.min.js +3 -3
  13. package/package.json +4 -3
  14. package/skill/margaui/SKILL.md +0 -105
  15. package/skill/margaui/components/accordion.md +0 -127
  16. package/skill/margaui/components/alert.md +0 -174
  17. package/skill/margaui/components/aura.md +0 -97
  18. package/skill/margaui/components/avatar.md +0 -220
  19. package/skill/margaui/components/badge.md +0 -193
  20. package/skill/margaui/components/breadcrumbs.md +0 -103
  21. package/skill/margaui/components/button.md +0 -322
  22. package/skill/margaui/components/calendar.md +0 -67
  23. package/skill/margaui/components/card.md +0 -373
  24. package/skill/margaui/components/carousel.md +0 -387
  25. package/skill/margaui/components/chat.md +0 -171
  26. package/skill/margaui/components/checkbox.md +0 -101
  27. package/skill/margaui/components/collapse.md +0 -172
  28. package/skill/margaui/components/countdown.md +0 -165
  29. package/skill/margaui/components/diff.md +0 -53
  30. package/skill/margaui/components/divider.md +0 -107
  31. package/skill/margaui/components/dock.md +0 -173
  32. package/skill/margaui/components/drawer.md +0 -184
  33. package/skill/margaui/components/dropdown.md +0 -388
  34. package/skill/margaui/components/fab.md +0 -346
  35. package/skill/margaui/components/fieldset.md +0 -88
  36. package/skill/margaui/components/file-input.md +0 -84
  37. package/skill/margaui/components/filter.md +0 -52
  38. package/skill/margaui/components/footer.md +0 -583
  39. package/skill/margaui/components/hero.md +0 -135
  40. package/skill/margaui/components/hover-3d.md +0 -129
  41. package/skill/margaui/components/hover-gallery.md +0 -49
  42. package/skill/margaui/components/indicator.md +0 -265
  43. package/skill/margaui/components/input.md +0 -389
  44. package/skill/margaui/components/join.md +0 -100
  45. package/skill/margaui/components/kbd.md +0 -127
  46. package/skill/margaui/components/label.md +0 -102
  47. package/skill/margaui/components/link.md +0 -96
  48. package/skill/margaui/components/list.md +0 -182
  49. package/skill/margaui/components/loading.md +0 -105
  50. package/skill/margaui/components/mask.md +0 -168
  51. package/skill/margaui/components/megamenu.md +0 -131
  52. package/skill/margaui/components/menu.md +0 -887
  53. package/skill/margaui/components/mockup-browser.md +0 -39
  54. package/skill/margaui/components/mockup-code.md +0 -81
  55. package/skill/margaui/components/mockup-phone.md +0 -39
  56. package/skill/margaui/components/mockup-window.md +0 -33
  57. package/skill/margaui/components/modal.md +0 -196
  58. package/skill/margaui/components/navbar.md +0 -282
  59. package/skill/margaui/components/otp.md +0 -171
  60. package/skill/margaui/components/pagination.md +0 -122
  61. package/skill/margaui/components/progress.md +0 -135
  62. package/skill/margaui/components/radial-progress.md +0 -67
  63. package/skill/margaui/components/radio.md +0 -133
  64. package/skill/margaui/components/range.md +0 -134
  65. package/skill/margaui/components/rating.md +0 -170
  66. package/skill/margaui/components/select.md +0 -225
  67. package/skill/margaui/components/skeleton.md +0 -64
  68. package/skill/margaui/components/stack.md +0 -142
  69. package/skill/margaui/components/stat.md +0 -254
  70. package/skill/margaui/components/status.md +0 -73
  71. package/skill/margaui/components/steps.md +0 -138
  72. package/skill/margaui/components/swap.md +0 -152
  73. package/skill/margaui/components/tab.md +0 -248
  74. package/skill/margaui/components/table.md +0 -1018
  75. package/skill/margaui/components/text-rotate.md +0 -91
  76. package/skill/margaui/components/textarea.md +0 -85
  77. package/skill/margaui/components/theme-controller.md +0 -266
  78. package/skill/margaui/components/timeline.md +0 -1356
  79. package/skill/margaui/components/toast.md +0 -165
  80. package/skill/margaui/components/toggle.md +0 -135
  81. package/skill/margaui/components/tooltip.md +0 -181
  82. package/skill/margaui/components/validator.md +0 -163
  83. package/skill/tutuca/SKILL.md +0 -56
  84. package/skill/tutuca/advanced.md +0 -212
  85. package/skill/tutuca/cli.md +0 -239
  86. package/skill/tutuca/component-design.md +0 -168
  87. package/skill/tutuca/core.md +0 -908
  88. package/skill/tutuca/iteration.md +0 -207
  89. package/skill/tutuca/macros.md +0 -86
  90. package/skill/tutuca/margaui.md +0 -175
  91. package/skill/tutuca/messages-and-intents.md +0 -399
  92. package/skill/tutuca/patterns/README.md +0 -48
  93. package/skill/tutuca/patterns/add-a-story.md +0 -26
  94. package/skill/tutuca/patterns/bind-text-and-attributes.md +0 -30
  95. package/skill/tutuca/patterns/conditional-attribute-value.md +0 -29
  96. package/skill/tutuca/patterns/coordinate-components.md +0 -54
  97. package/skill/tutuca/patterns/edit-through-a-dynamic-target.md +0 -27
  98. package/skill/tutuca/patterns/enrich-each-item.md +0 -25
  99. package/skill/tutuca/patterns/file-input.md +0 -39
  100. package/skill/tutuca/patterns/filter-a-list.md +0 -25
  101. package/skill/tutuca/patterns/filter-and-paginate.md +0 -60
  102. package/skill/tutuca/patterns/handle-events.md +0 -38
  103. package/skill/tutuca/patterns/iterate-a-list.md +0 -18
  104. package/skill/tutuca/patterns/paginate-a-list.md +0 -29
  105. package/skill/tutuca/patterns/render-a-child-component.md +0 -21
  106. package/skill/tutuca/patterns/reuse-markup-with-macros.md +0 -36
  107. package/skill/tutuca/patterns/share-state-across-the-tree.md +0 -38
  108. package/skill/tutuca/patterns/show-or-hide-content.md +0 -23
  109. package/skill/tutuca/patterns/switch-between-views.md +0 -30
  110. package/skill/tutuca/patterns/tabbed-interface.md +0 -43
  111. package/skill/tutuca/semantics.md +0 -195
  112. package/skill/tutuca/storybook.md +0 -270
  113. package/skill/tutuca/styles.md +0 -48
  114. package/skill/tutuca/testing.md +0 -346
  115. package/skill/tutuca-source/SKILL.md +0 -33
  116. package/skill/tutuca-source/tutuca.ext.js +0 -4235
@@ -52,13 +52,6 @@ var Storybook = component({
52
52
  };
53
53
  }
54
54
  },
55
- alter: {
56
- // The sidebar render-each shows only visible groups (kept positional via `when`
57
- // so a click resolves to the right group — see SidebarGroup.rowVisible).
58
- groupVisible(_key, group) {
59
- return group.visible;
60
- }
61
- },
62
55
  receive: {
63
56
  onApplyFilter(draft, value, ctx) {
64
57
  ctx.intent("persistState", [this.toUrlState({ sectionFilter: value }), this, false], {
@@ -160,6 +153,13 @@ var Storybook = component({
160
153
  setSelectedSectionFilter(draft, value);
161
154
  }
162
155
  },
156
+ alter: {
157
+ // The sidebar render-each shows only visible groups (kept positional via `when`
158
+ // so a click resolves to the right group — see SidebarGroup.rowVisible).
159
+ groupVisible(_key, group) {
160
+ return group.visible;
161
+ }
162
+ },
163
163
  view: html`<div>
164
164
  <div class="flex flex-col gap-3 p-3 h-screen" @show="truthy? .focusExample">
165
165
  <div class="flex justify-end">
@@ -250,15 +250,10 @@ var Section = component({
250
250
  // ignored here (rendered ungrouped) rather than coerced; the normalize layer
251
251
  // (tools/core/module.js) reports it as a shape error.
252
252
  group: typeof group === "string" ? group : "",
253
- items: items.map((v) => Example.Class.fromData(v))
253
+ items: items.map((v) => Example.fromData(v))
254
254
  });
255
255
  }
256
256
  },
257
- alter: {
258
- filterItem(_key, item) {
259
- return this.filter === "" || fuzzyMatch(this.filter, `${item.title} ${item.description}`);
260
- }
261
- },
262
257
  receive: {
263
258
  onApplyFilter(draft, value, ctx) {
264
259
  ctx.intent("exampleFilterChanged", [value], { route: ["dyn"] });
@@ -282,6 +277,11 @@ var Section = component({
282
277
  return this;
283
278
  }
284
279
  },
280
+ alter: {
281
+ filterItem(_key, item) {
282
+ return this.filter === "" || fuzzyMatch(this.filter, `${item.title} ${item.description}`);
283
+ }
284
+ },
285
285
  view: html`<section class="flex flex-col gap-3">
286
286
  <div class="sticky top-0 z-10 bg-base-100 pt-1 pb-2 shadow-sm">
287
287
  <h2 class="text-lg font-bold" @text=".title"></h2>
@@ -323,6 +323,12 @@ var SidebarEntry = component({
323
323
  var SidebarGroup = component({
324
324
  name: "SidebarGroup",
325
325
  fields: { name: "", collapsed: false, visible: true, rows: [] },
326
+ receive: {
327
+ onToggle(draft, ctx) {
328
+ ctx.intent("groupToggled", [this.name], { route: ["dyn"] });
329
+ return this;
330
+ }
331
+ },
326
332
  // Visibility drives the render-each `when` predicates (not `@show` on the items):
327
333
  // a `when` filter renders only visible rows while keeping each row's positional key,
328
334
  // so an event's path resolves to the right row. `@show` on a render-each item would
@@ -332,12 +338,6 @@ var SidebarGroup = component({
332
338
  return row.visible;
333
339
  }
334
340
  },
335
- receive: {
336
- onToggle(draft, ctx) {
337
- ctx.intent("groupToggled", [this.name], { route: ["dyn"] });
338
- return this;
339
- }
340
- },
341
341
  view: html`<div class="flex flex-col">
342
342
  <div
343
343
  class="list-row cursor-pointer hover:bg-base-200 font-semibold flex items-center gap-1"
@@ -411,6 +411,14 @@ var Example = component({
411
411
  });
412
412
  }
413
413
  },
414
+ methods: {
415
+ // An `intent` on the `dyn` leg leaves the example and walks into the storybook
416
+ // engine's own components. Nothing to warn about: if nothing answers, the walk
417
+ // runs out and the example hears `<name>Unhandled`.
418
+ runPhase(ctx, phase) {
419
+ dispatchPhase(ctx, ctx.at.field("value").buildPath(), phase, this.value);
420
+ }
421
+ },
414
422
  // Lifecycle hooks: the section forwards init/resume/suspend here; each runs the
415
423
  // matching `on` phase's actions against this example's component (`.value`).
416
424
  receive: {
@@ -446,14 +454,6 @@ var Example = component({
446
454
  draft.activeTab = value;
447
455
  }
448
456
  },
449
- methods: {
450
- // An `intent` on the `dyn` leg leaves the example and walks into the storybook
451
- // engine's own components. Nothing to warn about: if nothing answers, the walk
452
- // runs out and the example hears `<name>Unhandled`.
453
- runPhase(ctx, phase) {
454
- dispatchPhase(ctx, ctx.at.field("value").buildPath(), phase, this.value);
455
- }
456
- },
457
457
  view: html`<div class="card card-border bg-base-100 shadow-md">
458
458
  <div class="card-body">
459
459
  <h2 class="card-title flex justify-between">
@@ -678,7 +678,7 @@ function buildStorybook(modules) {
678
678
  if (raw == null) return [];
679
679
  return Array.isArray(raw) ? raw : [raw];
680
680
  });
681
- const sections = rawSections.map((s) => Section.Class.fromData(s)).sort((a, b) => a.title.localeCompare(b.title));
681
+ const sections = rawSections.map((s) => Section.fromData(s)).sort((a, b) => a.title.localeCompare(b.title));
682
682
  const engineComponents = [
683
683
  Storybook,
684
684
  Section,
@@ -713,7 +713,7 @@ function buildStorybook(modules) {
713
713
  }
714
714
  const components = [.../* @__PURE__ */ new Set([...engineComponents, ...moduleComponents.flat()])];
715
715
  return {
716
- root: Storybook.Class.withSections(sections),
716
+ root: Storybook.withSections(sections),
717
717
  components,
718
718
  engineComponents,
719
719
  moduleComponents,
@@ -2076,13 +2076,12 @@ function processXExtras(node, attrs, opName, startIdx, px) {
2076
2076
  const a = attrs[i];
2077
2077
  const aName = a.name;
2078
2078
  if (consumed.has(aName)) continue;
2079
- const atPrefixed = aName.charCodeAt(0) === 64;
2080
- const baseName = atPrefixed ? aName.slice(1) : aName;
2081
- const wrapper = wrappable ? X_OPS[baseName]?.wrapper : null;
2082
- if (wrapper) {
2083
- if (!atPrefixed) maybeDeprecateBareXDirective(px, opName, baseName);
2084
- wrappers.push([wrapper, parseBool(a.value, px)]);
2085
- continue;
2079
+ if (wrappable && aName.charCodeAt(0) === 64) {
2080
+ const wrapper = X_OPS[aName.slice(1)]?.wrapper;
2081
+ if (wrapper) {
2082
+ wrappers.push([wrapper, parseBool(a.value, px)]);
2083
+ continue;
2084
+ }
2086
2085
  }
2087
2086
  const issueInfo = { op: opName, name: aName, value: a.value };
2088
2087
  px.onParseIssue("unknown-x-attr", issueInfo);
@@ -2094,9 +2093,6 @@ function processXExtras(node, attrs, opName, startIdx, px) {
2094
2093
  }
2095
2094
  return node;
2096
2095
  }
2097
- function maybeDeprecateBareXDirective(px, opName, name) {
2098
- px.onDeprecatedSyntax("bare-x-directive", { op: opName, name });
2099
- }
2100
2096
  function wrap(node, px, wrappers) {
2101
2097
  if (wrappers) {
2102
2098
  for (let i = wrappers.length - 1; i >= 0; i--) {
@@ -2218,17 +2214,10 @@ function parseRenderEach(px, value, as, attrs) {
2218
2214
  const attrParser = getAttrParser(px);
2219
2215
  const eachAttr = attrParser.pushWrapper("each", value, seqVal);
2220
2216
  attrParser.eachAttr = eachAttr;
2221
- const when = attrs.getNamedItem("@when") ?? attrs.getNamedItem("when");
2222
- if (when) {
2223
- if (when.name.charCodeAt(0) !== 64) maybeDeprecateBareXDirective(px, "render-each", "when");
2224
- attrParser._parseWhen(when.value);
2225
- }
2226
- const lWith = attrs.getNamedItem("@loop-with") ?? attrs.getNamedItem("loop-with");
2227
- if (lWith) {
2228
- if (lWith.name.charCodeAt(0) !== 64)
2229
- maybeDeprecateBareXDirective(px, "render-each", "loop-with");
2230
- attrParser._parseLoopWith(lWith.value);
2231
- }
2217
+ const when = attrs.getNamedItem("@when");
2218
+ if (when) attrParser._parseWhen(when.value);
2219
+ const lWith = attrs.getNamedItem("@loop-with");
2220
+ if (lWith) attrParser._parseLoopWith(lWith.value);
2232
2221
  const each = px.addNodeIf(EachNode, seqVal);
2233
2222
  each.iterInfo.whenVal = eachAttr.whenVal ?? null;
2234
2223
  each.iterInfo.loopWithVal = eachAttr.loopWithVal ?? null;
@@ -2366,10 +2355,8 @@ var X_OPS = {
2366
2355
  render: xOp(["as"], { wrappable: true, ignoresChildren: true }),
2367
2356
  "render-it": xOp(["as"], { wrappable: true, ignoresChildren: true }),
2368
2357
  // `@when`/`@loop-with` are consumed here (handled in parseRenderEach) so
2369
- // `processXExtras` does not flag them as unknown attrs. TEMPORARY: the bare
2370
- // `when`/`loop-with` spellings are deprecated in favor of the `@` form — see
2371
- // maybeDeprecateBareXDirective (added 2026-07-08).
2372
- "render-each": xOp(["as", "when", "loop-with", "@when", "@loop-with"], {
2358
+ // `processXExtras` does not flag them as unknown attrs.
2359
+ "render-each": xOp(["as", "@when", "@loop-with"], {
2373
2360
  wrappable: true,
2374
2361
  ignoresChildren: true
2375
2362
  }),
@@ -2460,10 +2447,6 @@ var ParseContext = class _ParseContext {
2460
2447
  onParseIssue(kind, info) {
2461
2448
  console.warn(`tutuca parse issue [${kind}]`, info);
2462
2449
  }
2463
- // Lint-only channel for deprecation nudges on still-valid syntax; the base
2464
- // (runtime) context ignores them so live apps stay quiet. See LintParseContext.
2465
- onDeprecatedSyntax(_kind, _info) {
2466
- }
2467
2450
  };
2468
2451
  var _htmlBlockTags = "ADDRESS,ARTICLE,ASIDE,BLOCKQUOTE,CAPTION,COL,COLGROUP,DETAILS,DIALOG,DIV,DD,DL,DT,FIELDSET,FIGCAPTION,FIGURE,FOOTER,FORM,H1,H2,H3,H4,H5,H6,HEADER,HGROUP,HR,LEGEND,LI,MAIN,MENU,NAV,OL,P,PRE,SECTION,SUMMARY,TABLE,TBODY,TD,TFOOT,TH,THEAD,TR,UL";
2469
2452
  var HTML_BLOCK_TAGS = new Set(_htmlBlockTags.split(","));
@@ -2600,20 +2583,20 @@ function compileModifiers(eventName, names) {
2600
2583
  }
2601
2584
 
2602
2585
  // src/components.js
2586
+ var COMPONENT = /* @__PURE__ */ Symbol.for("tutuca.component");
2603
2587
  var Components = class {
2604
2588
  constructor() {
2605
- this.getComponentSymbol = /* @__PURE__ */ Symbol("getComponent");
2606
2589
  this.byId = /* @__PURE__ */ new Map();
2607
2590
  }
2608
- registerComponent(comp) {
2609
- comp.Class.prototype[this.getComponentSymbol] = () => comp;
2610
- this.byId.set(comp.id, comp);
2591
+ registerComponent(Comp) {
2592
+ this.byId.set(Comp[COMPONENT].id, Comp);
2611
2593
  }
2612
2594
  getComponentForId(id) {
2613
2595
  return this.byId.get(id) ?? null;
2614
2596
  }
2615
2597
  getCompFor(v) {
2616
- return v?.[this.getComponentSymbol]?.() ?? null;
2598
+ const Comp = v?.constructor;
2599
+ return Comp?.[COMPONENT] ? Comp : null;
2617
2600
  }
2618
2601
  getHandlerFor(v, name, key) {
2619
2602
  return this.getCompFor(v)?.[key][name] ?? null;
@@ -2644,11 +2627,10 @@ var ComponentStack = class _ComponentStack {
2644
2627
  registerComponents(comps, opts) {
2645
2628
  const { aliases = {} } = opts ?? {};
2646
2629
  for (let i = 0; i < comps.length; i++) {
2647
- const comp = comps[i];
2648
- comp.scope = this.enter();
2649
- comp.Class.scope = comp.scope;
2650
- this.comps.registerComponent(comp);
2651
- this.byName[comp.name] = comp;
2630
+ const Comp = comps[i];
2631
+ Comp[COMPONENT].scope = this.enter();
2632
+ this.comps.registerComponent(Comp);
2633
+ this.byName[Comp.name] = Comp;
2652
2634
  }
2653
2635
  for (const alias in aliases) {
2654
2636
  const comp = this.byName[aliases[alias]];
@@ -3032,7 +3014,7 @@ var FieldFloat = class extends Field {
3032
3014
  super("float", name, CHECK_TYPE_FLOAT, (_) => null, defaultValue);
3033
3015
  }
3034
3016
  };
3035
- var getTypeName = (v) => v?.constructor?.getMetaClass?.()?.name;
3017
+ var getTypeName = (v) => v?.constructor?.[COMPONENT]?.name ?? v?.constructor?.getMetaClass?.()?.name ?? null;
3036
3018
  var CheckTypeName = class {
3037
3019
  constructor(typeName) {
3038
3020
  this.typeName = typeName;
@@ -3133,7 +3115,7 @@ var ClassBuilder = class {
3133
3115
  getMetaClass: () => metaClass,
3134
3116
  make(inArgs = {}, opts = {}) {
3135
3117
  const args = {};
3136
- const scope = opts.scope ?? this.scope;
3118
+ const scope = opts.scope ?? this[COMPONENT]?.scope ?? this.scope;
3137
3119
  for (const key in inArgs) {
3138
3120
  const field = fields[key];
3139
3121
  if (compFields.has(key)) args[key] = mkCompField(field, scope, inArgs[key]);
@@ -3213,7 +3195,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
3213
3195
  return b.build();
3214
3196
  }
3215
3197
  function validateDraftFields(current, draft) {
3216
- const meta = current?.constructor?.getMetaClass?.();
3198
+ const meta = current?.constructor?.[COMPONENT] ?? current?.constructor?.getMetaClass?.();
3217
3199
  if (!meta) return;
3218
3200
  for (const [name, field] of Object.entries(meta.fields)) {
3219
3201
  const value = draft[name];
@@ -3226,7 +3208,33 @@ function validateDraftFields(current, draft) {
3226
3208
  }
3227
3209
  }
3228
3210
  }
3229
- Component.fromSpec = (opts) => new Component(classFromData(opts.name, opts), opts);
3211
+ var META_KEYS = "name id fields methods views receive intent alter provide lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
3212
+ " "
3213
+ );
3214
+ Component.fromSpec = (opts) => {
3215
+ const Class = classFromData(opts.name, opts);
3216
+ const comp = new Component(Class, opts);
3217
+ const metaClass = Class.getMetaClass();
3218
+ comp.fields = metaClass.fields;
3219
+ comp.methods = metaClass.methods;
3220
+ Class.getMetaClass = () => comp;
3221
+ Class[COMPONENT] = comp;
3222
+ for (const key of META_KEYS)
3223
+ if (!Object.hasOwn(Class, key))
3224
+ Object.defineProperty(Class, key, {
3225
+ get() {
3226
+ return comp[key];
3227
+ },
3228
+ set(v) {
3229
+ comp[key] = v;
3230
+ },
3231
+ configurable: true
3232
+ });
3233
+ for (const key of Object.getOwnPropertyNames(Component.prototype))
3234
+ if (key !== "constructor" && key !== "make" && !Object.hasOwn(Class, key))
3235
+ Class[key] = (...args) => comp[key](...args);
3236
+ return Class;
3237
+ };
3230
3238
  var component = (opts) => Component.fromSpec(opts);
3231
3239
 
3232
3240
  // src/transactor.js
@@ -3381,8 +3389,8 @@ var Transaction = class {
3381
3389
  whenSettled() {
3382
3390
  return this.completion.whenSettled();
3383
3391
  }
3384
- // Resolves once this transaction AND all transitively-derived work (sends, bubbles,
3385
- // requests and the responses they produce, recursively) have settled.
3392
+ // Resolves once this transaction AND all transitively-derived work (sends and
3393
+ // intents, including the answers they produce, recursively) have settled.
3386
3394
  whenSubtreeSettled() {
3387
3395
  return this.completion.whenSubtreeSettled();
3388
3396
  }
@@ -3556,7 +3564,7 @@ var NameArgsTransaction = class extends Transaction {
3556
3564
  }
3557
3565
  handlerProp = null;
3558
3566
  // NameArgs verbs map their handler bucket straight to the observed kind:
3559
- // receive / bubble / response / input.
3567
+ // receive / intent.
3560
3568
  get observeKind() {
3561
3569
  return this.handlerProp;
3562
3570
  }
@@ -4215,6 +4223,7 @@ function tutuca(nodeOrSelector) {
4215
4223
  return new App(rootNode, comps, renderer, ParseContext);
4216
4224
  }
4217
4225
  export {
4226
+ COMPONENT,
4218
4227
  FIELD_CLASS,
4219
4228
  PASS,
4220
4229
  ParseContext,
package/dist/tutuca.js CHANGED
@@ -2779,13 +2779,12 @@ function processXExtras(node, attrs, opName, startIdx, px) {
2779
2779
  const a = attrs[i];
2780
2780
  const aName = a.name;
2781
2781
  if (consumed.has(aName)) continue;
2782
- const atPrefixed = aName.charCodeAt(0) === 64;
2783
- const baseName = atPrefixed ? aName.slice(1) : aName;
2784
- const wrapper = wrappable ? X_OPS[baseName]?.wrapper : null;
2785
- if (wrapper) {
2786
- if (!atPrefixed) maybeDeprecateBareXDirective(px, opName, baseName);
2787
- wrappers.push([wrapper, parseBool(a.value, px)]);
2788
- continue;
2782
+ if (wrappable && aName.charCodeAt(0) === 64) {
2783
+ const wrapper = X_OPS[aName.slice(1)]?.wrapper;
2784
+ if (wrapper) {
2785
+ wrappers.push([wrapper, parseBool(a.value, px)]);
2786
+ continue;
2787
+ }
2789
2788
  }
2790
2789
  const issueInfo = { op: opName, name: aName, value: a.value };
2791
2790
  px.onParseIssue("unknown-x-attr", issueInfo);
@@ -2797,9 +2796,6 @@ function processXExtras(node, attrs, opName, startIdx, px) {
2797
2796
  }
2798
2797
  return node;
2799
2798
  }
2800
- function maybeDeprecateBareXDirective(px, opName, name) {
2801
- px.onDeprecatedSyntax("bare-x-directive", { op: opName, name });
2802
- }
2803
2799
  function wrap(node, px, wrappers) {
2804
2800
  if (wrappers) {
2805
2801
  for (let i = wrappers.length - 1; i >= 0; i--) {
@@ -2921,17 +2917,10 @@ function parseRenderEach(px, value, as, attrs) {
2921
2917
  const attrParser = getAttrParser(px);
2922
2918
  const eachAttr = attrParser.pushWrapper("each", value, seqVal);
2923
2919
  attrParser.eachAttr = eachAttr;
2924
- const when = attrs.getNamedItem("@when") ?? attrs.getNamedItem("when");
2925
- if (when) {
2926
- if (when.name.charCodeAt(0) !== 64) maybeDeprecateBareXDirective(px, "render-each", "when");
2927
- attrParser._parseWhen(when.value);
2928
- }
2929
- const lWith = attrs.getNamedItem("@loop-with") ?? attrs.getNamedItem("loop-with");
2930
- if (lWith) {
2931
- if (lWith.name.charCodeAt(0) !== 64)
2932
- maybeDeprecateBareXDirective(px, "render-each", "loop-with");
2933
- attrParser._parseLoopWith(lWith.value);
2934
- }
2920
+ const when = attrs.getNamedItem("@when");
2921
+ if (when) attrParser._parseWhen(when.value);
2922
+ const lWith = attrs.getNamedItem("@loop-with");
2923
+ if (lWith) attrParser._parseLoopWith(lWith.value);
2935
2924
  const each2 = px.addNodeIf(EachNode, seqVal);
2936
2925
  each2.iterInfo.whenVal = eachAttr.whenVal ?? null;
2937
2926
  each2.iterInfo.loopWithVal = eachAttr.loopWithVal ?? null;
@@ -3069,10 +3058,8 @@ var X_OPS = {
3069
3058
  render: xOp(["as"], { wrappable: true, ignoresChildren: true }),
3070
3059
  "render-it": xOp(["as"], { wrappable: true, ignoresChildren: true }),
3071
3060
  // `@when`/`@loop-with` are consumed here (handled in parseRenderEach) so
3072
- // `processXExtras` does not flag them as unknown attrs. TEMPORARY: the bare
3073
- // `when`/`loop-with` spellings are deprecated in favor of the `@` form — see
3074
- // maybeDeprecateBareXDirective (added 2026-07-08).
3075
- "render-each": xOp(["as", "when", "loop-with", "@when", "@loop-with"], {
3061
+ // `processXExtras` does not flag them as unknown attrs.
3062
+ "render-each": xOp(["as", "@when", "@loop-with"], {
3076
3063
  wrappable: true,
3077
3064
  ignoresChildren: true
3078
3065
  }),
@@ -3163,10 +3150,6 @@ var ParseContext = class _ParseContext {
3163
3150
  onParseIssue(kind, info) {
3164
3151
  console.warn(`tutuca parse issue [${kind}]`, info);
3165
3152
  }
3166
- // Lint-only channel for deprecation nudges on still-valid syntax; the base
3167
- // (runtime) context ignores them so live apps stay quiet. See LintParseContext.
3168
- onDeprecatedSyntax(_kind, _info) {
3169
- }
3170
3153
  };
3171
3154
  var _htmlBlockTags = "ADDRESS,ARTICLE,ASIDE,BLOCKQUOTE,CAPTION,COL,COLGROUP,DETAILS,DIALOG,DIV,DD,DL,DT,FIELDSET,FIGCAPTION,FIGURE,FOOTER,FORM,H1,H2,H3,H4,H5,H6,HEADER,HGROUP,HR,LEGEND,LI,MAIN,MENU,NAV,OL,P,PRE,SECTION,SUMMARY,TABLE,TBODY,TD,TFOOT,TH,THEAD,TR,UL";
3172
3155
  var HTML_BLOCK_TAGS = new Set(_htmlBlockTags.split(","));
@@ -3303,20 +3286,20 @@ function compileModifiers(eventName, names) {
3303
3286
  }
3304
3287
 
3305
3288
  // src/components.js
3289
+ var COMPONENT = /* @__PURE__ */ Symbol.for("tutuca.component");
3306
3290
  var Components = class {
3307
3291
  constructor() {
3308
- this.getComponentSymbol = /* @__PURE__ */ Symbol("getComponent");
3309
3292
  this.byId = /* @__PURE__ */ new Map();
3310
3293
  }
3311
- registerComponent(comp) {
3312
- comp.Class.prototype[this.getComponentSymbol] = () => comp;
3313
- this.byId.set(comp.id, comp);
3294
+ registerComponent(Comp) {
3295
+ this.byId.set(Comp[COMPONENT].id, Comp);
3314
3296
  }
3315
3297
  getComponentForId(id) {
3316
3298
  return this.byId.get(id) ?? null;
3317
3299
  }
3318
3300
  getCompFor(v) {
3319
- return v?.[this.getComponentSymbol]?.() ?? null;
3301
+ const Comp = v?.constructor;
3302
+ return Comp?.[COMPONENT] ? Comp : null;
3320
3303
  }
3321
3304
  getHandlerFor(v, name, key) {
3322
3305
  return this.getCompFor(v)?.[key][name] ?? null;
@@ -3347,11 +3330,10 @@ var ComponentStack = class _ComponentStack {
3347
3330
  registerComponents(comps, opts) {
3348
3331
  const { aliases = {} } = opts ?? {};
3349
3332
  for (let i = 0; i < comps.length; i++) {
3350
- const comp = comps[i];
3351
- comp.scope = this.enter();
3352
- comp.Class.scope = comp.scope;
3353
- this.comps.registerComponent(comp);
3354
- this.byName[comp.name] = comp;
3333
+ const Comp = comps[i];
3334
+ Comp[COMPONENT].scope = this.enter();
3335
+ this.comps.registerComponent(Comp);
3336
+ this.byName[Comp.name] = Comp;
3355
3337
  }
3356
3338
  for (const alias in aliases) {
3357
3339
  const comp = this.byName[aliases[alias]];
@@ -3735,7 +3717,7 @@ var FieldFloat = class extends Field {
3735
3717
  super("float", name, CHECK_TYPE_FLOAT, (_) => null, defaultValue);
3736
3718
  }
3737
3719
  };
3738
- var getTypeName = (v) => v?.constructor?.getMetaClass?.()?.name;
3720
+ var getTypeName = (v) => v?.constructor?.[COMPONENT]?.name ?? v?.constructor?.getMetaClass?.()?.name ?? null;
3739
3721
  var CheckTypeName = class {
3740
3722
  constructor(typeName) {
3741
3723
  this.typeName = typeName;
@@ -3836,7 +3818,7 @@ var ClassBuilder = class {
3836
3818
  getMetaClass: () => metaClass,
3837
3819
  make(inArgs = {}, opts = {}) {
3838
3820
  const args = {};
3839
- const scope = opts.scope ?? this.scope;
3821
+ const scope = opts.scope ?? this[COMPONENT]?.scope ?? this.scope;
3840
3822
  for (const key in inArgs) {
3841
3823
  const field = fields[key];
3842
3824
  if (compFields.has(key)) args[key] = mkCompField(field, scope, inArgs[key]);
@@ -3916,7 +3898,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
3916
3898
  return b.build();
3917
3899
  }
3918
3900
  function validateDraftFields(current2, draft) {
3919
- const meta = current2?.constructor?.getMetaClass?.();
3901
+ const meta = current2?.constructor?.[COMPONENT] ?? current2?.constructor?.getMetaClass?.();
3920
3902
  if (!meta) return;
3921
3903
  for (const [name, field] of Object.entries(meta.fields)) {
3922
3904
  const value = draft[name];
@@ -3929,7 +3911,33 @@ function validateDraftFields(current2, draft) {
3929
3911
  }
3930
3912
  }
3931
3913
  }
3932
- Component.fromSpec = (opts) => new Component(classFromData(opts.name, opts), opts);
3914
+ var META_KEYS = "name id fields methods views receive intent alter provide lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
3915
+ " "
3916
+ );
3917
+ Component.fromSpec = (opts) => {
3918
+ const Class = classFromData(opts.name, opts);
3919
+ const comp = new Component(Class, opts);
3920
+ const metaClass = Class.getMetaClass();
3921
+ comp.fields = metaClass.fields;
3922
+ comp.methods = metaClass.methods;
3923
+ Class.getMetaClass = () => comp;
3924
+ Class[COMPONENT] = comp;
3925
+ for (const key of META_KEYS)
3926
+ if (!Object.hasOwn(Class, key))
3927
+ Object.defineProperty(Class, key, {
3928
+ get() {
3929
+ return comp[key];
3930
+ },
3931
+ set(v) {
3932
+ comp[key] = v;
3933
+ },
3934
+ configurable: true
3935
+ });
3936
+ for (const key of Object.getOwnPropertyNames(Component.prototype))
3937
+ if (key !== "constructor" && key !== "make" && !Object.hasOwn(Class, key))
3938
+ Class[key] = (...args) => comp[key](...args);
3939
+ return Class;
3940
+ };
3933
3941
  var component = (opts) => Component.fromSpec(opts);
3934
3942
 
3935
3943
  // src/transactor.js
@@ -4084,8 +4092,8 @@ var Transaction = class {
4084
4092
  whenSettled() {
4085
4093
  return this.completion.whenSettled();
4086
4094
  }
4087
- // Resolves once this transaction AND all transitively-derived work (sends, bubbles,
4088
- // requests and the responses they produce, recursively) have settled.
4095
+ // Resolves once this transaction AND all transitively-derived work (sends and
4096
+ // intents, including the answers they produce, recursively) have settled.
4089
4097
  whenSubtreeSettled() {
4090
4098
  return this.completion.whenSubtreeSettled();
4091
4099
  }
@@ -4259,7 +4267,7 @@ var NameArgsTransaction = class extends Transaction {
4259
4267
  }
4260
4268
  handlerProp = null;
4261
4269
  // NameArgs verbs map their handler bucket straight to the observed kind:
4262
- // receive / bubble / response / input.
4270
+ // receive / intent.
4263
4271
  get observeKind() {
4264
4272
  return this.handlerProp;
4265
4273
  }
@@ -4918,6 +4926,7 @@ function tutuca(nodeOrSelector) {
4918
4926
  return new App(rootNode, comps, renderer, ParseContext);
4919
4927
  }
4920
4928
  export {
4929
+ COMPONENT,
4921
4930
  FIELD_CLASS,
4922
4931
  PASS,
4923
4932
  ParseContext,