nodality 1.3.14 → 1.3.15

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 (207) hide show
  1. package/bin/nodality.mjs +1 -1
  2. package/dist/animator.cjs.js.LICENSE.txt +1 -1
  3. package/dist/animator.esm.js.LICENSE.txt +1 -1
  4. package/dist/audionew.cjs.js.LICENSE.txt +1 -1
  5. package/dist/audionew.esm.js.LICENSE.txt +1 -1
  6. package/dist/base.cjs.js.LICENSE.txt +1 -1
  7. package/dist/base.esm.js.LICENSE.txt +1 -1
  8. package/dist/beta-desktop-bar.cjs.js.LICENSE.txt +1 -1
  9. package/dist/beta-desktop-bar.esm.js.LICENSE.txt +1 -1
  10. package/dist/beta-mobile-bar.cjs.js.LICENSE.txt +1 -1
  11. package/dist/beta-mobile-bar.esm.js.LICENSE.txt +1 -1
  12. package/dist/bundle.umd.js +1 -1
  13. package/dist/bundle.umd.js.LICENSE.txt +1 -1
  14. package/dist/button.cjs.js.LICENSE.txt +1 -1
  15. package/dist/button.esm.js.LICENSE.txt +1 -1
  16. package/dist/card-getter.cjs.js.LICENSE.txt +1 -1
  17. package/dist/card-getter.esm.js.LICENSE.txt +1 -1
  18. package/dist/center.cjs.js.LICENSE.txt +1 -1
  19. package/dist/center.esm.js.LICENSE.txt +1 -1
  20. package/dist/checkbox.cjs.js.LICENSE.txt +1 -1
  21. package/dist/checkbox.esm.js.LICENSE.txt +1 -1
  22. package/dist/code.cjs.js.LICENSE.txt +1 -1
  23. package/dist/code.esm.js.LICENSE.txt +1 -1
  24. package/dist/container.cjs.js.LICENSE.txt +1 -1
  25. package/dist/container.esm.js.LICENSE.txt +1 -1
  26. package/dist/data-list.cjs.js.LICENSE.txt +1 -1
  27. package/dist/data-list.esm.js.LICENSE.txt +1 -1
  28. package/dist/designer.cjs.js +1 -1
  29. package/dist/designer.cjs.js.LICENSE.txt +1 -1
  30. package/dist/designer.esm.js +1 -1
  31. package/dist/designer.esm.js.LICENSE.txt +1 -1
  32. package/dist/element-mapper.cjs.js +1 -1
  33. package/dist/element-mapper.cjs.js.LICENSE.txt +1 -1
  34. package/dist/element-mapper.esm.js +1 -1
  35. package/dist/element-mapper.esm.js.LICENSE.txt +1 -1
  36. package/dist/finalresult.esm.js +2 -2
  37. package/dist/finalresult.esm.js.LICENSE.txt +1 -1
  38. package/dist/flex-card.cjs.js.LICENSE.txt +1 -1
  39. package/dist/flex-card.esm.js.LICENSE.txt +1 -1
  40. package/dist/flex-grid.cjs.js.LICENSE.txt +1 -1
  41. package/dist/flex-grid.esm.js.LICENSE.txt +1 -1
  42. package/dist/flex-row.cjs.js.LICENSE.txt +1 -1
  43. package/dist/flex-row.esm.js.LICENSE.txt +1 -1
  44. package/dist/floating-input.cjs.js.LICENSE.txt +1 -1
  45. package/dist/floating-input.esm.js.LICENSE.txt +1 -1
  46. package/dist/free.cjs.js.LICENSE.txt +1 -1
  47. package/dist/free.esm.js.LICENSE.txt +1 -1
  48. package/dist/horizontal-scroller.cjs.js.LICENSE.txt +1 -1
  49. package/dist/horizontal-scroller.esm.js.LICENSE.txt +1 -1
  50. package/dist/image-picker.cjs.js.LICENSE.txt +1 -1
  51. package/dist/image-picker.esm.js.LICENSE.txt +1 -1
  52. package/dist/image.cjs.js.LICENSE.txt +1 -1
  53. package/dist/image.esm.js.LICENSE.txt +1 -1
  54. package/dist/index.cjs.js +1 -1
  55. package/dist/index.cjs.js.LICENSE.txt +1 -1
  56. package/dist/index.d.ts +20 -1
  57. package/dist/index.esm.js +2 -2
  58. package/dist/index.esm.js.LICENSE.txt +1 -1
  59. package/dist/keyframe-animation.cjs.js.LICENSE.txt +1 -1
  60. package/dist/keyframe-animation.esm.js.LICENSE.txt +1 -1
  61. package/dist/link-getter.cjs.js.LICENSE.txt +1 -1
  62. package/dist/link-getter.esm.js.LICENSE.txt +1 -1
  63. package/dist/link.cjs.js.LICENSE.txt +1 -1
  64. package/dist/link.esm.js.LICENSE.txt +1 -1
  65. package/dist/meta-adder.cjs.js.LICENSE.txt +1 -1
  66. package/dist/meta-adder.esm.js.LICENSE.txt +1 -1
  67. package/dist/modal-2025.cjs.js.LICENSE.txt +1 -1
  68. package/dist/modal-2025.esm.js.LICENSE.txt +1 -1
  69. package/dist/multiswitcher.cjs.js.LICENSE.txt +1 -1
  70. package/dist/multiswitcher.esm.js.LICENSE.txt +1 -1
  71. package/dist/new-nav-bar.cjs.js.LICENSE.txt +1 -1
  72. package/dist/new-nav-bar.esm.js.LICENSE.txt +1 -1
  73. package/dist/picker.cjs.js.LICENSE.txt +1 -1
  74. package/dist/picker.esm.js.LICENSE.txt +1 -1
  75. package/dist/progress.cjs.js.LICENSE.txt +1 -1
  76. package/dist/progress.esm.js.LICENSE.txt +1 -1
  77. package/dist/radio.cjs.js.LICENSE.txt +1 -1
  78. package/dist/radio.esm.js.LICENSE.txt +1 -1
  79. package/dist/range.cjs.js.LICENSE.txt +1 -1
  80. package/dist/range.esm.js.LICENSE.txt +1 -1
  81. package/dist/scroll-video.cjs.js.LICENSE.txt +1 -1
  82. package/dist/scroll-video.esm.js.LICENSE.txt +1 -1
  83. package/dist/side-bar.cjs.js.LICENSE.txt +1 -1
  84. package/dist/side-bar.esm.js.LICENSE.txt +1 -1
  85. package/dist/side-nav-bar.cjs.js.LICENSE.txt +1 -1
  86. package/dist/side-nav-bar.esm.js.LICENSE.txt +1 -1
  87. package/dist/simple-bar.cjs.js.LICENSE.txt +1 -1
  88. package/dist/simple-bar.esm.js.LICENSE.txt +1 -1
  89. package/dist/slider-2025.cjs.js.LICENSE.txt +1 -1
  90. package/dist/slider-2025.esm.js.LICENSE.txt +1 -1
  91. package/dist/spacer.cjs.js.LICENSE.txt +1 -1
  92. package/dist/spacer.esm.js.LICENSE.txt +1 -1
  93. package/dist/stack.cjs.js.LICENSE.txt +1 -1
  94. package/dist/stack.esm.js.LICENSE.txt +1 -1
  95. package/dist/stacker.cjs.js.LICENSE.txt +1 -1
  96. package/dist/stacker.esm.js.LICENSE.txt +1 -1
  97. package/dist/table.cjs.js.LICENSE.txt +1 -1
  98. package/dist/table.esm.js.LICENSE.txt +1 -1
  99. package/dist/text-field.cjs.js.LICENSE.txt +1 -1
  100. package/dist/text-field.esm.js.LICENSE.txt +1 -1
  101. package/dist/text.cjs.js.LICENSE.txt +1 -1
  102. package/dist/text.esm.js.LICENSE.txt +1 -1
  103. package/dist/theme.cjs.js.LICENSE.txt +1 -1
  104. package/dist/theme.esm.js.LICENSE.txt +1 -1
  105. package/dist/transform-anim.cjs.js.LICENSE.txt +1 -1
  106. package/dist/transform-anim.esm.js.LICENSE.txt +1 -1
  107. package/dist/ulist.cjs.js.LICENSE.txt +1 -1
  108. package/dist/ulist.esm.js.LICENSE.txt +1 -1
  109. package/dist/video.cjs.js.LICENSE.txt +1 -1
  110. package/dist/video.esm.js.LICENSE.txt +1 -1
  111. package/dist/wrap.cjs.js.LICENSE.txt +1 -1
  112. package/dist/wrap.esm.js.LICENSE.txt +1 -1
  113. package/dist/zoom-card.cjs.js.LICENSE.txt +1 -1
  114. package/dist/zoom-card.esm.js.LICENSE.txt +1 -1
  115. package/layout/animator.js +1 -1
  116. package/layout/audio.js +1 -1
  117. package/layout/audionew.js +1 -1
  118. package/layout/base.js +1 -1
  119. package/layout/beta-desktop-bar.js +1 -1
  120. package/layout/beta-mobile-bar.js +1 -1
  121. package/layout/button.js +1 -1
  122. package/layout/center.js +1 -1
  123. package/layout/checkbox.js +1 -1
  124. package/layout/circle.js +1 -1
  125. package/layout/code.js +1 -1
  126. package/layout/container.js +1 -1
  127. package/layout/dropdown-2025.js +1 -1
  128. package/layout/flex-card.js +1 -1
  129. package/layout/flex-grid.js +1 -1
  130. package/layout/flex-row.js +1 -1
  131. package/layout/form-components/custom.js +1 -1
  132. package/layout/form-components/data-list.js +1 -1
  133. package/layout/form-components/floating-input.js +1 -1
  134. package/layout/form-components/form-all.js +1 -1
  135. package/layout/form-components/form.js +1 -1
  136. package/layout/form-components/image-picker.js +1 -1
  137. package/layout/form-components/picker.js +1 -1
  138. package/layout/form-components/radio.js +1 -1
  139. package/layout/form-components/radiogroup.js +1 -1
  140. package/layout/form-components/range.js +1 -1
  141. package/layout/free.js +1 -1
  142. package/layout/grid-overlay.js +1 -1
  143. package/layout/grid-switcher.js +1 -1
  144. package/layout/grid.js +1 -1
  145. package/layout/horizontal-scroller.js +1 -1
  146. package/layout/image.js +1 -1
  147. package/layout/index.js +5 -1
  148. package/layout/link.js +1 -1
  149. package/layout/list.js +1 -1
  150. package/layout/meta-adder.js +1 -1
  151. package/layout/modal-2025.js +1 -1
  152. package/layout/morph.js +1 -1
  153. package/layout/multiswitcher.js +1 -1
  154. package/layout/nav-bar.js +1 -1
  155. package/layout/nav-factor/custom-div.js +1 -1
  156. package/layout/new-nav-bar.js +1 -1
  157. package/layout/polygon.js +1 -1
  158. package/layout/prerender-site.js +1 -1
  159. package/layout/prerender.js +1 -1
  160. package/layout/progress.js +1 -1
  161. package/layout/row.js +1 -1
  162. package/layout/scroll-video.js +1 -1
  163. package/layout/shop.js +261 -0
  164. package/layout/side-bar.js +1 -1
  165. package/layout/side-nav-bar.js +1 -1
  166. package/layout/simple-bar.js +1 -1
  167. package/layout/slider-2025.js +1 -1
  168. package/layout/spacer.js +1 -1
  169. package/layout/stack.js +1 -1
  170. package/layout/svg.js +1 -1
  171. package/layout/switcher.js +1 -1
  172. package/layout/table.js +1 -1
  173. package/layout/text-field.js +1 -1
  174. package/layout/text.js +1 -1
  175. package/layout/ulist.js +1 -1
  176. package/layout/video.js +1 -1
  177. package/layout/wrap.js +1 -1
  178. package/layout/zoom-card.js +1 -1
  179. package/lib/agent-surface.js +24 -2
  180. package/lib/card-getter.js +1 -1
  181. package/lib/check-page.js +1 -1
  182. package/lib/codegen.js +1 -1
  183. package/lib/data.js +1 -1
  184. package/lib/designer.js +3 -2
  185. package/lib/element-mapper.js +116 -1
  186. package/lib/element-params.generated.js +4 -4
  187. package/lib/grid-geometry.js +1 -1
  188. package/lib/keyframe-animation.js +1 -1
  189. package/lib/link-getter.js +1 -1
  190. package/lib/morph-node.js +1 -1
  191. package/lib/normalize-spec.js +1 -1
  192. package/lib/parse-html.js +1 -1
  193. package/lib/raster-inspect.js +1 -1
  194. package/lib/raster-ops.js +1 -1
  195. package/lib/raster-presets.js +1 -1
  196. package/lib/resolve-refs.js +1 -1
  197. package/lib/scroll-video.js +1 -1
  198. package/lib/seo.js +1 -1
  199. package/lib/stacker.js +1 -1
  200. package/lib/suggest.js +1 -1
  201. package/lib/theme.js +1 -1
  202. package/lib/transform-anim.js +1 -1
  203. package/lib/transition.js +1 -1
  204. package/lib/validate-nodes.js +42 -4
  205. package/lib/webmcp-adapter.js +36 -1
  206. package/package.json +1 -1
  207. package/schema.json +1000 -2
package/lib/theme.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.14
2
+ * nodality v1.3.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.14
2
+ * nodality v1.3.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/lib/transition.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.14
2
+ * nodality v1.3.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.14
2
+ * nodality v1.3.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -167,7 +167,7 @@ const EDGE_FIELDS = [
167
167
  * what it exposes is DERIVED, so there is nothing here to describe the
168
168
  * tools with — only which parts of the page may be reached.
169
169
  */
170
- const AGENT_SURFACE_FIELDS = ["op", "name", "forms", "exclude"];
170
+ const AGENT_SURFACE_FIELDS = ["op", "name", "forms", "exclude", "products"];
171
171
 
172
172
  /**
173
173
  * Design ops that may be written as a BARE STRING, `{ op: "gradient" }`,
@@ -277,6 +277,7 @@ export const CONTENT_SLOT = {
277
277
  cards: "items", nav: "items", sideNav: "items", table: "items", ulist: "items",
278
278
  dropdown: "items", picker: "items", radio: "items",
279
279
  row: "children", form: "children", stack: "children", wrap: "children",
280
+ product: "children",
280
281
  };
281
282
 
282
283
  // Of the types that read `items`, which read the entries as ELEMENT SPECS
@@ -417,6 +418,36 @@ export function validateNodes(nodes, elements, defs) {
417
418
  ? resolveRefs(elements, defs)
418
419
  : elements;
419
420
 
421
+ // Commerce order. A `product` looks for the page's `store` the moment
422
+ // it is attached; Des attaches in array order, so a product rendered
423
+ // before the store stays empty, and the only report is a console error
424
+ // in the browser. Found by building a product page with the store at the
425
+ // end, where it looked tidy.
426
+ if (Array.isArray(toWalk)) {
427
+ let storeAt = null;
428
+ const products = [];
429
+ const visit = (list, base) => {
430
+ if (!Array.isArray(list)) return;
431
+ list.forEach((el, i) => {
432
+ if (!el || typeof el !== "object") return;
433
+ const p = `${base}[${i}]`;
434
+ if (el.type === "store" && storeAt === null) storeAt = p;
435
+ if (el.type === "product") products.push({ p, before: storeAt === null });
436
+ visit(el.children, `${p}.children`);
437
+ });
438
+ };
439
+ visit(toWalk, "elements");
440
+ if (products.length && storeAt === null) {
441
+ warn("NO_STORE", products[0].p, "product", ["{ type: \"store\", domain: \"https://your-shop.example\" }"],
442
+ ["a store element placed before the first product"]);
443
+ } else {
444
+ for (const { p } of products.filter((x) => x.before)) {
445
+ warn("STORE_AFTER_PRODUCT", p, "product", [`move ${storeAt} before this product`],
446
+ ["the store element first: a product finds its store when it is attached"]);
447
+ }
448
+ }
449
+ }
450
+
420
451
  // An alias and its canonical name both present, disagreeing: one of them
421
452
  // is going to be ignored. The author hears it here rather than finding it
422
453
  // in the page.
@@ -728,11 +759,13 @@ export function validateNodes(nodes, elements, defs) {
728
759
  // form of the silent no-op, and an agent has no way to see
729
760
  // that the tool it expected was never registered.
730
761
  const formIds = [];
762
+ const productIds = [];
731
763
  const walkForms = (list) => {
732
764
  if (!Array.isArray(list)) return;
733
765
  for (const el of list) {
734
766
  if (!el || typeof el !== "object") continue;
735
767
  if (el.type === "form" && typeof el.id === "string") formIds.push(el.id);
768
+ if (el.type === "product" && typeof el.id === "string") productIds.push(el.id.replace(/^#/, ""));
736
769
  walkForms(el.children);
737
770
  }
738
771
  };
@@ -743,7 +776,7 @@ export function validateNodes(nodes, elements, defs) {
743
776
  ["a string used to prefix every derived tool name"]);
744
777
  }
745
778
 
746
- for (const key of ["forms", "exclude"]) {
779
+ for (const key of ["forms", "exclude", "products"]) {
747
780
  if (node[key] === undefined) continue;
748
781
  if (!Array.isArray(node[key])) {
749
782
  push("BAD_FIELD", `${path}.${key}`, node[key], [], ["an array of ids"]);
@@ -763,6 +796,10 @@ export function validateNodes(nodes, elements, defs) {
763
796
  if (idsKnown && !formIds.includes(bare)) {
764
797
  push("UNKNOWN_FORM", at, v, suggest(bare, formIds), formIds);
765
798
  }
799
+ } else if (key === "products") {
800
+ if (idsKnown && !productIds.includes(bare)) {
801
+ push("UNKNOWN_PRODUCT", at, v, suggest(bare, productIds), productIds);
802
+ }
766
803
  } else if (idsKnown && !ids.includes(bare)) {
767
804
  push("UNKNOWN_STATE", at, v, suggest(bare, ids), ids);
768
805
  }
@@ -775,7 +812,8 @@ export function validateNodes(nodes, elements, defs) {
775
812
  // in the expectation of more says so.
776
813
  const hasChain = nodes.some((n) => n && n.op === "morph");
777
814
  const hasForms = Array.isArray(node.forms) && node.forms.length > 0;
778
- if (!hasChain && !hasForms) {
815
+ const hasProducts = Array.isArray(node.products) && node.products.length > 0;
816
+ if (!hasChain && !hasForms && !hasProducts) {
779
817
  push("EMPTY_SURFACE", path, node, [],
780
818
  ["add a { op: \"morph\" } node, or name a form in `forms`"]);
781
819
  }
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.14
2
+ * nodality v1.3.15
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -265,6 +265,41 @@ export function installAgentSurface({ mount, elements, nodes, morphs }) {
265
265
 
266
266
  read: async () => ({ ok: true, view: currentView(), ...readSubtree(currentSubtree()) }),
267
267
 
268
+ // What the product box shows now: the live rendering once Shopify has
269
+ // answered (its placeholder is hidden then), the static copy before.
270
+ product: async (args, tool) => {
271
+ const box = mount && mount.querySelector(`[id="${tool.productId}"]`);
272
+ if (!box) return refuse("NO_PRODUCT", tool.productId, []);
273
+ const ph = box.querySelector("[shopify-loading-placeholder]");
274
+ const live = ph && typeof window !== "undefined" && window.getComputedStyle(ph).display === "none";
275
+ // Its own reader, not readSubtree: a price and its options sit in
276
+ // inline elements and in Shopify's (open) shadow DOM, which a
277
+ // reader of headings and paragraphs never reaches. Visible text in
278
+ // document order; the template, scripts, styles and anything hidden
279
+ // — the placeholder once the live copy is up — are skipped.
280
+ const parts = [];
281
+ const actions = [];
282
+ const walk = (n) => {
283
+ for (const c of n.childNodes) {
284
+ if (c.nodeType === 3) {
285
+ const t = c.textContent.replace(/\s+/g, " ").trim();
286
+ if (t) parts.push(t);
287
+ } else if (c.nodeType === 1) {
288
+ if (/^(TEMPLATE|SCRIPT|STYLE)$/.test(c.tagName)) continue;
289
+ if (window.getComputedStyle(c).display === "none") continue;
290
+ if (/^(A|BUTTON)$/.test(c.tagName)) {
291
+ const t = c.textContent.replace(/\s+/g, " ").trim();
292
+ if (t && !actions.includes(t)) actions.push(t);
293
+ }
294
+ if (c.shadowRoot) walk(c.shadowRoot);
295
+ walk(c);
296
+ }
297
+ }
298
+ };
299
+ walk(box);
300
+ return { ok: true, product: tool.productId, handle: box.getAttribute("handle"), live: !!live, text: parts.join("\n"), actions };
301
+ },
302
+
268
303
  submit: async (args = {}, tool) => {
269
304
  const form = findForm(tool.formId);
270
305
  if (!form) return refuse("NO_FORM", tool.formId, []);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodality",
3
- "version": "1.3.14",
3
+ "version": "1.3.15",
4
4
  "description": "A lightweight library for declarative UI elements.",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",