nodality 1.3.12 → 1.3.14

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 (213) hide show
  1. package/dist/animator.cjs.js.LICENSE.txt +1 -1
  2. package/dist/animator.esm.js.LICENSE.txt +1 -1
  3. package/dist/audionew.cjs.js.LICENSE.txt +1 -1
  4. package/dist/audionew.esm.js.LICENSE.txt +1 -1
  5. package/dist/base.cjs.js.LICENSE.txt +1 -1
  6. package/dist/base.esm.js.LICENSE.txt +1 -1
  7. package/dist/beta-desktop-bar.cjs.js +1 -1
  8. package/dist/beta-desktop-bar.cjs.js.LICENSE.txt +1 -1
  9. package/dist/beta-desktop-bar.esm.js +1 -1
  10. package/dist/beta-desktop-bar.esm.js.LICENSE.txt +1 -1
  11. package/dist/beta-mobile-bar.cjs.js +1 -1
  12. package/dist/beta-mobile-bar.cjs.js.LICENSE.txt +1 -1
  13. package/dist/beta-mobile-bar.esm.js +1 -1
  14. package/dist/beta-mobile-bar.esm.js.LICENSE.txt +1 -1
  15. package/dist/bundle.umd.js +1 -1
  16. package/dist/bundle.umd.js.LICENSE.txt +1 -1
  17. package/dist/button.cjs.js.LICENSE.txt +1 -1
  18. package/dist/button.esm.js.LICENSE.txt +1 -1
  19. package/dist/card-getter.cjs.js.LICENSE.txt +1 -1
  20. package/dist/card-getter.esm.js.LICENSE.txt +1 -1
  21. package/dist/center.cjs.js.LICENSE.txt +1 -1
  22. package/dist/center.esm.js.LICENSE.txt +1 -1
  23. package/dist/checkbox.cjs.js.LICENSE.txt +1 -1
  24. package/dist/checkbox.esm.js.LICENSE.txt +1 -1
  25. package/dist/code.cjs.js.LICENSE.txt +1 -1
  26. package/dist/code.esm.js.LICENSE.txt +1 -1
  27. package/dist/container.cjs.js.LICENSE.txt +1 -1
  28. package/dist/container.esm.js.LICENSE.txt +1 -1
  29. package/dist/data-list.cjs.js.LICENSE.txt +1 -1
  30. package/dist/data-list.esm.js.LICENSE.txt +1 -1
  31. package/dist/designer.cjs.js +1 -1
  32. package/dist/designer.cjs.js.LICENSE.txt +1 -1
  33. package/dist/designer.esm.js +1 -1
  34. package/dist/designer.esm.js.LICENSE.txt +1 -1
  35. package/dist/element-mapper.cjs.js +1 -1
  36. package/dist/element-mapper.cjs.js.LICENSE.txt +1 -1
  37. package/dist/element-mapper.esm.js +1 -1
  38. package/dist/element-mapper.esm.js.LICENSE.txt +1 -1
  39. package/dist/finalresult.esm.js +1 -1
  40. package/dist/finalresult.esm.js.LICENSE.txt +1 -1
  41. package/dist/flex-card.cjs.js.LICENSE.txt +1 -1
  42. package/dist/flex-card.esm.js.LICENSE.txt +1 -1
  43. package/dist/flex-grid.cjs.js.LICENSE.txt +1 -1
  44. package/dist/flex-grid.esm.js.LICENSE.txt +1 -1
  45. package/dist/flex-row.cjs.js.LICENSE.txt +1 -1
  46. package/dist/flex-row.esm.js.LICENSE.txt +1 -1
  47. package/dist/floating-input.cjs.js.LICENSE.txt +1 -1
  48. package/dist/floating-input.esm.js.LICENSE.txt +1 -1
  49. package/dist/free.cjs.js.LICENSE.txt +1 -1
  50. package/dist/free.esm.js.LICENSE.txt +1 -1
  51. package/dist/horizontal-scroller.cjs.js.LICENSE.txt +1 -1
  52. package/dist/horizontal-scroller.esm.js.LICENSE.txt +1 -1
  53. package/dist/image-picker.cjs.js.LICENSE.txt +1 -1
  54. package/dist/image-picker.esm.js.LICENSE.txt +1 -1
  55. package/dist/image.cjs.js +1 -1
  56. package/dist/image.cjs.js.LICENSE.txt +1 -1
  57. package/dist/image.esm.js +1 -1
  58. package/dist/image.esm.js.LICENSE.txt +1 -1
  59. package/dist/index.cjs.js +1 -1
  60. package/dist/index.cjs.js.LICENSE.txt +1 -1
  61. package/dist/index.d.ts +3 -2
  62. package/dist/index.esm.js +1 -1
  63. package/dist/index.esm.js.LICENSE.txt +1 -1
  64. package/dist/keyframe-animation.cjs.js.LICENSE.txt +1 -1
  65. package/dist/keyframe-animation.esm.js.LICENSE.txt +1 -1
  66. package/dist/link-getter.cjs.js.LICENSE.txt +1 -1
  67. package/dist/link-getter.esm.js.LICENSE.txt +1 -1
  68. package/dist/link.cjs.js.LICENSE.txt +1 -1
  69. package/dist/link.esm.js.LICENSE.txt +1 -1
  70. package/dist/meta-adder.cjs.js.LICENSE.txt +1 -1
  71. package/dist/meta-adder.esm.js.LICENSE.txt +1 -1
  72. package/dist/modal-2025.cjs.js.LICENSE.txt +1 -1
  73. package/dist/modal-2025.esm.js.LICENSE.txt +1 -1
  74. package/dist/multiswitcher.cjs.js +1 -1
  75. package/dist/multiswitcher.cjs.js.LICENSE.txt +1 -1
  76. package/dist/multiswitcher.esm.js +1 -1
  77. package/dist/multiswitcher.esm.js.LICENSE.txt +1 -1
  78. package/dist/new-nav-bar.cjs.js.LICENSE.txt +1 -1
  79. package/dist/new-nav-bar.esm.js.LICENSE.txt +1 -1
  80. package/dist/picker.cjs.js.LICENSE.txt +1 -1
  81. package/dist/picker.esm.js.LICENSE.txt +1 -1
  82. package/dist/progress.cjs.js.LICENSE.txt +1 -1
  83. package/dist/progress.esm.js.LICENSE.txt +1 -1
  84. package/dist/radio.cjs.js.LICENSE.txt +1 -1
  85. package/dist/radio.esm.js.LICENSE.txt +1 -1
  86. package/dist/range.cjs.js.LICENSE.txt +1 -1
  87. package/dist/range.esm.js.LICENSE.txt +1 -1
  88. package/dist/scroll-video.cjs.js.LICENSE.txt +1 -1
  89. package/dist/scroll-video.esm.js.LICENSE.txt +1 -1
  90. package/dist/side-bar.cjs.js.LICENSE.txt +1 -1
  91. package/dist/side-bar.esm.js.LICENSE.txt +1 -1
  92. package/dist/side-nav-bar.cjs.js.LICENSE.txt +1 -1
  93. package/dist/side-nav-bar.esm.js.LICENSE.txt +1 -1
  94. package/dist/simple-bar.cjs.js.LICENSE.txt +1 -1
  95. package/dist/simple-bar.esm.js.LICENSE.txt +1 -1
  96. package/dist/slider-2025.cjs.js.LICENSE.txt +1 -1
  97. package/dist/slider-2025.esm.js.LICENSE.txt +1 -1
  98. package/dist/spacer.cjs.js.LICENSE.txt +1 -1
  99. package/dist/spacer.esm.js.LICENSE.txt +1 -1
  100. package/dist/stack.cjs.js.LICENSE.txt +1 -1
  101. package/dist/stack.esm.js.LICENSE.txt +1 -1
  102. package/dist/stacker.cjs.js.LICENSE.txt +1 -1
  103. package/dist/stacker.esm.js.LICENSE.txt +1 -1
  104. package/dist/table.cjs.js.LICENSE.txt +1 -1
  105. package/dist/table.esm.js.LICENSE.txt +1 -1
  106. package/dist/text-field.cjs.js.LICENSE.txt +1 -1
  107. package/dist/text-field.esm.js.LICENSE.txt +1 -1
  108. package/dist/text.cjs.js.LICENSE.txt +1 -1
  109. package/dist/text.esm.js.LICENSE.txt +1 -1
  110. package/dist/theme.cjs.js.LICENSE.txt +1 -1
  111. package/dist/theme.esm.js.LICENSE.txt +1 -1
  112. package/dist/transform-anim.cjs.js.LICENSE.txt +1 -1
  113. package/dist/transform-anim.esm.js.LICENSE.txt +1 -1
  114. package/dist/ulist.cjs.js.LICENSE.txt +1 -1
  115. package/dist/ulist.esm.js.LICENSE.txt +1 -1
  116. package/dist/video.cjs.js.LICENSE.txt +1 -1
  117. package/dist/video.esm.js.LICENSE.txt +1 -1
  118. package/dist/wrap.cjs.js.LICENSE.txt +1 -1
  119. package/dist/wrap.esm.js.LICENSE.txt +1 -1
  120. package/dist/zoom-card.cjs.js.LICENSE.txt +1 -1
  121. package/dist/zoom-card.esm.js.LICENSE.txt +1 -1
  122. package/layout/animator.js +1 -1
  123. package/layout/audio.js +1 -1
  124. package/layout/audionew.js +1 -1
  125. package/layout/base.js +1 -1
  126. package/layout/beta-desktop-bar.js +4 -1
  127. package/layout/beta-mobile-bar.js +35 -13
  128. package/layout/button.js +1 -1
  129. package/layout/center.js +1 -1
  130. package/layout/checkbox.js +1 -1
  131. package/layout/circle.js +1 -1
  132. package/layout/code.js +1 -1
  133. package/layout/container.js +1 -1
  134. package/layout/dropdown-2025.js +1 -1
  135. package/layout/flex-card.js +1 -1
  136. package/layout/flex-grid.js +1 -1
  137. package/layout/flex-row.js +1 -1
  138. package/layout/form-components/custom.js +1 -1
  139. package/layout/form-components/data-list.js +1 -1
  140. package/layout/form-components/floating-input.js +1 -1
  141. package/layout/form-components/form-all.js +1 -1
  142. package/layout/form-components/form.js +1 -1
  143. package/layout/form-components/image-picker.js +1 -1
  144. package/layout/form-components/picker.js +1 -1
  145. package/layout/form-components/radio.js +1 -1
  146. package/layout/form-components/radiogroup.js +1 -1
  147. package/layout/form-components/range.js +1 -1
  148. package/layout/free.js +1 -1
  149. package/layout/grid-overlay.js +1 -1
  150. package/layout/grid-switcher.js +1 -1
  151. package/layout/grid.js +1 -1
  152. package/layout/horizontal-scroller.js +1 -1
  153. package/layout/image.js +92 -1
  154. package/layout/index.js +1 -1
  155. package/layout/link.js +1 -1
  156. package/layout/list.js +1 -1
  157. package/layout/meta-adder.js +1 -1
  158. package/layout/modal-2025.js +1 -1
  159. package/layout/morph.js +1 -1
  160. package/layout/multiswitcher.js +15 -2
  161. package/layout/nav-bar.js +1 -1
  162. package/layout/nav-factor/custom-div.js +1 -1
  163. package/layout/new-nav-bar.js +1 -1
  164. package/layout/polygon.js +1 -1
  165. package/layout/prerender-site.js +1 -1
  166. package/layout/prerender.js +14 -9
  167. package/layout/progress.js +1 -1
  168. package/layout/row.js +1 -1
  169. package/layout/scroll-video.js +1 -1
  170. package/layout/side-bar.js +1 -1
  171. package/layout/side-nav-bar.js +1 -1
  172. package/layout/simple-bar.js +1 -1
  173. package/layout/slider-2025.js +1 -1
  174. package/layout/spacer.js +1 -1
  175. package/layout/stack.js +1 -1
  176. package/layout/svg.js +1 -1
  177. package/layout/switcher.js +1 -1
  178. package/layout/table.js +1 -1
  179. package/layout/text-field.js +1 -1
  180. package/layout/text.js +1 -1
  181. package/layout/ulist.js +1 -1
  182. package/layout/video.js +1 -1
  183. package/layout/wrap.js +1 -1
  184. package/layout/zoom-card.js +1 -1
  185. package/lib/agent-surface.js +1 -1
  186. package/lib/card-getter.js +1 -1
  187. package/lib/check-page.js +1 -1
  188. package/lib/codegen.js +1 -1
  189. package/lib/data.js +1 -1
  190. package/lib/designer.js +1 -1
  191. package/lib/element-mapper.js +71 -1
  192. package/lib/element-params.generated.js +4 -4
  193. package/lib/grid-geometry.js +1 -1
  194. package/lib/keyframe-animation.js +1 -1
  195. package/lib/link-getter.js +1 -1
  196. package/lib/morph-node.js +1 -1
  197. package/lib/normalize-spec.js +1 -1
  198. package/lib/parse-html.js +1 -1
  199. package/lib/raster-inspect.js +1 -1
  200. package/lib/raster-ops.js +1 -1
  201. package/lib/raster-presets.js +1 -1
  202. package/lib/resolve-refs.js +1 -1
  203. package/lib/scroll-video.js +1 -1
  204. package/lib/seo.js +1 -1
  205. package/lib/stacker.js +1 -1
  206. package/lib/suggest.js +1 -1
  207. package/lib/theme.js +1 -1
  208. package/lib/transform-anim.js +1 -1
  209. package/lib/transition.js +1 -1
  210. package/lib/validate-nodes.js +1 -1
  211. package/lib/webmcp-adapter.js +1 -1
  212. package/package.json +1 -1
  213. package/schema.json +42 -10
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -54,6 +54,9 @@ class /*Beta*/DesktopBar extends Animator { // add set method for background col
54
54
  if (obj.hamburgerColour) {
55
55
  this.hamburgerColour = obj.hamburgerColour;
56
56
  }
57
+ // Last, so a page's values replace the defaults setStyles() wrote.
58
+ obj.color && (this.res.style.color = obj.color);
59
+ obj.keySet && this.keySet(obj.keySet);
57
60
  return this;
58
61
  }
59
62
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -39,15 +39,18 @@ let repl = this.removeQuotesFromFirstWord(JSON.stringify(this.obj));
39
39
 
40
40
  // 23:38:35 Yes!!! 23/04/2025
41
41
  // Alway construct neste in this way
42
- let codeObj = `
43
- background: "${this.obj.background}",
44
- brand: ${this.obj.brand.toCode()},
45
- mar: ${JSON.stringify(this.obj.mar)},
46
- pad: ${JSON.stringify(this.obj.pad)},
47
- resmar: ${JSON.stringify(this.obj.resmar)},
48
- respad: ${JSON.stringify(this.obj.respad)},
49
- radius: ${JSON.stringify(this.obj.radius)},
50
- `;
42
+ // Des renders by running this code, so an option left out of it never
43
+ // reaches the page — hamburgerColour was read by set() and dropped here.
44
+ // Every option set() reads is emitted; brand only when there is one (it
45
+ // threw on a bar without a brand).
46
+ const SERIALISED = ["background", "color", "mar", "pad", "resmar", "respad", "radius", "maxHeight", "hamburgerColour", "keySet", "menuLabel", "menuId"];
47
+ let codeObj = SERIALISED
48
+ .filter((k) => this.obj[k] !== undefined)
49
+ .map((k) => `${k}: ${JSON.stringify(this.obj[k])},`)
50
+ .join("\n");
51
+ if (this.obj.brand && typeof this.obj.brand.toCode === "function") {
52
+ codeObj += `\nbrand: ${[].concat(this.obj.brand.toCode()).join("")},`;
53
+ }
51
54
 
52
55
  return `new MobileBar().set({${codeObj}}).add([
53
56
  ${items.join(",")}
@@ -92,9 +95,12 @@ radius: ${JSON.stringify(this.obj.radius)},
92
95
  this.hamburgerColour = obj.hamburgerColour;
93
96
  }
94
97
 
95
-
96
-
97
98
  this.setStyles(obj);
99
+
100
+ // After setStyles, so a page's values replace the defaults.
101
+ obj.color && (this.navbar.style.color = obj.color);
102
+ obj.pad && this.pad(obj.pad);
103
+ obj.keySet && this.keySet(obj.keySet);
98
104
  return this;
99
105
  }
100
106
 
@@ -143,7 +149,6 @@ console.log(newTextInstance.render());*/
143
149
  //}
144
150
 
145
151
  if (obj.brand && typeof newTextInstance.render === "function") {
146
- console.log("Appending brand:", newTextInstance.render());
147
152
  this.brand.appendChild(newTextInstance.render());
148
153
  } else {
149
154
  }
@@ -156,9 +161,25 @@ if (obj.brand && typeof newTextInstance.render === "function") {
156
161
  this.toggleButton = document.createElement('button');
157
162
  this.toggleButton.classList.add('navbar-toggle');
158
163
  this.toggleButton.innerHTML = '☰'; // Hamburger icon
164
+ // A glyph is not a name: without these a screen reader announced the
165
+ // button as "☰" and could not tell whether the menu was open.
166
+ this.toggleButton.setAttribute('type', 'button');
167
+ this.toggleButton.setAttribute('aria-label', obj.menuLabel ?? 'Menu');
168
+ this.toggleButton.setAttribute('aria-expanded', 'false');
159
169
 
160
170
  this.navContent = document.createElement('div');
161
171
  this.navContent.classList.add('navbar-content');
172
+ if (obj.menuId) {
173
+ this.navContent.setAttribute('id', obj.menuId);
174
+ this.toggleButton.setAttribute('aria-controls', obj.menuId);
175
+ }
176
+ // Following a link closes the menu. On a one-page site the links are
177
+ // anchors, and a menu left open covered the section it had jumped to.
178
+ this.navContent.addEventListener('click', (e) => {
179
+ if (this.isMobileNavOpen && e.target && e.target.closest && e.target.closest('a')) {
180
+ this.toggleMobileNav();
181
+ }
182
+ });
162
183
 
163
184
  this.navbarHeader.appendChild(this.brand);
164
185
  this.navbarHeader.appendChild(this.toggleButton);
@@ -213,6 +234,7 @@ if (obj.brand && typeof newTextInstance.render === "function") {
213
234
 
214
235
  toggleMobileNav() {
215
236
  this.isMobileNavOpen = !this.isMobileNavOpen;
237
+ this.toggleButton.setAttribute('aria-expanded', String(this.isMobileNavOpen));
216
238
  this.navContent.style.display = this.isMobileNavOpen ? 'flex' : 'none';
217
239
  if (this.isMobileNavOpen) {
218
240
  this.navContent.style.flexDirection = 'column';
package/layout/button.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/center.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/circle.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/code.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/free.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/grid.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/image.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -272,6 +272,9 @@ let obj = options;
272
272
  options.clipPath && this.clipPath(options.clipPath);
273
273
  options.clipPath && (stra += `clipPath: "${options.clipPath}", \n`);
274
274
 
275
+ //@ img.reveal {object}: Reveal the image through a mask as it scrolls into view: {mask: "square", size: 0.3, duration: "1.2s", easing, zoom: 1.12, offset: 0.2, delay: "0s", once: true}. It starts as a centred square `size` × its shorter side and opens to the full frame once the square rises `offset` of the viewport height above the bottom edge. Owns clip-path and scale while it runs; reduced-motion visitors, and pages with no IntersectionObserver (the prerender), get the image unmasked.
276
+ options.reveal && this.reveal(options.reveal);
277
+
275
278
 
276
279
  // console.log("261");
277
280
  // console.warn(obj);
@@ -674,6 +677,94 @@ if (mqa.matches){
674
677
  return this;
675
678
  }
676
679
 
680
+ /**
681
+ * Scroll reveal through a mask. The masked state is applied only where it
682
+ * can be undone: with no window, no IntersectionObserver (the jsdom
683
+ * prerender) or a reduced-motion preference the image stays unmasked,
684
+ * because a mask that never opens hides the content for good.
685
+ *
686
+ * The square is a true square: clip-path's inset() percentages resolve
687
+ * per axis, so on a portrait or wide frame a percentage inset draws a
688
+ * rectangle. The insets are measured in px instead and re-measured when
689
+ * the frame resizes; the percentage form is only the pre-layout guess.
690
+ *
691
+ * The zoom uses the `scale` property, not `transform`, so it composes with
692
+ * any transform the page sets instead of overwriting it.
693
+ */
694
+ reveal(opts) {
695
+ const el = this.res;
696
+ const o = opts && typeof opts === "object" ? opts : {};
697
+ const mask = o.mask ?? "square";
698
+ if (mask !== "square") {
699
+ console.warn(`nodality: img.reveal mask "${mask}" is not supported — use "square".`);
700
+ return this;
701
+ }
702
+ if (typeof window === "undefined" || typeof window.IntersectionObserver !== "function") return this;
703
+ const reduced = typeof window.matchMedia === "function" &&
704
+ window.matchMedia("(prefers-reduced-motion: reduce)").matches;
705
+ if (reduced) return this;
706
+
707
+ const size = Math.min(1, Math.max(0, Number(o.size ?? 0.3)));
708
+ const duration = o.duration ?? "1.2s";
709
+ const easing = o.easing ?? "cubic-bezier(0.76, 0, 0.24, 1)";
710
+ const delay = o.delay ?? "0s";
711
+ const zoom = Number(o.zoom ?? 1.12);
712
+ const once = o.once !== false;
713
+ const transition = ["clip-path", "scale"].map((p) => `${p} ${duration} ${easing} ${delay}`).join(", ");
714
+
715
+ let open = false;
716
+ const closed = () => {
717
+ const w = el.clientWidth, h = el.clientHeight;
718
+ if (!w || !h) return `inset(${(1 - size) * 50}% ${(1 - size) * 50}%)`;
719
+ const s = Math.min(w, h) * size;
720
+ return `inset(${(h - s) / 2}px ${(w - s) / 2}px)`;
721
+ };
722
+ // Re-measuring a closed mask must not animate: the frame's first
723
+ // layout would otherwise play as a 1.2s morph from the guess.
724
+ const settle = () => {
725
+ el.style.transition = "none";
726
+ el.style.clipPath = closed();
727
+ void el.offsetWidth;
728
+ el.style.transition = transition;
729
+ };
730
+
731
+ el.style.clipPath = closed();
732
+ el.style.scale = String(zoom);
733
+ el.style.willChange = "clip-path, scale";
734
+ el.style.transition = transition;
735
+
736
+ const ro = typeof window.ResizeObserver === "function"
737
+ ? new window.ResizeObserver(() => { if (!open) settle(); })
738
+ : null;
739
+ ro && ro.observe(el);
740
+
741
+ // Triggered by a LINE, not an area ratio: the browser clips the target
742
+ // by its own clip-path when it measures the intersection, so a closed
743
+ // square never shows more than its own share of the frame (about 8% at
744
+ // size 0.3) and a `threshold` of 0.35 would never be reached. Instead
745
+ // the square opens once it rises `offset` of the viewport above the
746
+ // bottom edge.
747
+ const offset = Math.min(0.9, Math.max(0, Number(o.offset ?? 0.2)));
748
+ const io = new window.IntersectionObserver((entries) => {
749
+ for (const entry of entries) {
750
+ if (entry.isIntersecting && !open) {
751
+ open = true;
752
+ el.style.clipPath = "inset(0px 0px)";
753
+ el.style.scale = "1";
754
+ if (once) { io.disconnect(); ro && ro.disconnect(); }
755
+ } else if (!entry.isIntersecting && open && !once) {
756
+ open = false;
757
+ el.style.clipPath = closed();
758
+ el.style.scale = String(zoom);
759
+ }
760
+ }
761
+ }, { threshold: 0, rootMargin: `0px 0px ${-offset * 100}% 0px` });
762
+ io.observe(el);
763
+
764
+ el.addEventListener("transitionend", () => { if (open && once) el.style.willChange = "auto"; });
765
+ return this;
766
+ }
767
+
677
768
  clipPath(pathData) {
678
769
  // Create a unique ID for the clip path
679
770
 
package/layout/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/link.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/list.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/morph.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -117,8 +117,21 @@ str += `{ at: "${this.options.breakpoints[i].at}", view: ${this.options.breakpoi
117
117
 
118
118
  applyView() {
119
119
 
120
+ // No matchMedia at all (a bare jsdom — the prerenderer installs its own,
121
+ // other hosts may not): show the widest view rather than an empty box.
122
+ // The browser re-runs this with real queries when it rebuilds the page.
123
+ if (typeof window.matchMedia !== "function") {
124
+ const widest = this.breakpoints.reduce((a, b) => (parseFloat(b.at) > parseFloat(a.at) ? b : a), this.breakpoints[0]);
125
+ if (widest && this.currentView !== widest.view.render()) {
126
+ this.internalDiv.innerHTML = "";
127
+ this.internalDiv.appendChild(widest.view.render());
128
+ this.currentView = widest.view.render();
129
+ }
130
+ return;
131
+ }
132
+
120
133
  // check if we are in range
121
-
134
+
122
135
  const width = window.innerWidth;
123
136
 
124
137
  let rstart = this.breakpoints.map(el => el.at);
package/layout/nav-bar.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/polygon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -263,14 +263,19 @@ export async function prerender({
263
263
  window.matchMedia = (query) => {
264
264
  let matches = false;
265
265
  if (typeof query === "string" && query.includes("width")) {
266
- // Parse a single "(min-width: 768px)" or "(max-width: 768px)"
267
- // clause. Multi-clause queries (commas, `and`) fall through to
268
- // false — Nodality's breakpoint code doesn't emit those.
269
- const min = query.match(/min-width:\s*(\d+)\s*px/i);
270
- const max = query.match(/max-width:\s*(\d+)\s*px/i);
271
- if (min && !max) matches = vw >= Number(min[1]);
272
- else if (max && !min) matches = vw <= Number(max[1]);
273
- // Both present (range) or other → leave as false.
266
+ // Every min-width / max-width clause must hold, so a range —
267
+ // "(min-width: 0px) and (max-width: 1199px)" — resolves too. It
268
+ // used to fall through to false on the claim that Nodality never
269
+ // emits one, but the Switcher behind every `nav` does: no range
270
+ // matched during SSG, and every nav shipped as an empty box.
271
+ // Comma lists (OR) are still answered false.
272
+ if (!query.includes(",")) {
273
+ const min = query.match(/min-width:\s*([\d.]+)\s*px/i);
274
+ const max = query.match(/max-width:\s*([\d.]+)\s*px/i);
275
+ if (min || max) {
276
+ matches = (!min || vw >= Number(min[1])) && (!max || vw <= Number(max[1]));
277
+ }
278
+ }
274
279
  }
275
280
  return {
276
281
  matches,
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/row.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/spacer.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/stack.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.12
2
+ * nodality v1.3.14
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */