nodality 1.0.147 → 1.0.149

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 (94) hide show
  1. package/layout/animator.js +1 -1
  2. package/layout/audio.js +1 -1
  3. package/layout/audionew.js +1 -1
  4. package/layout/base-2.js +1 -1
  5. package/layout/base.js +1 -1
  6. package/layout/beta-desktop-bar.js +1 -1
  7. package/layout/beta-mobile-bar.js +1 -1
  8. package/layout/box.js +1 -1
  9. package/layout/button.js +1 -1
  10. package/layout/cards.js +1 -1
  11. package/layout/center.js +1 -1
  12. package/layout/checkbox.js +1 -1
  13. package/layout/circle.js +1 -1
  14. package/layout/clean-row.js +1 -1
  15. package/layout/code.js +1 -1
  16. package/layout/container.js +1 -1
  17. package/layout/custom.js +1 -1
  18. package/layout/div-image.js +1 -1
  19. package/layout/dropdown-2025.js +1 -1
  20. package/layout/dropdown.js +1 -1
  21. package/layout/empty-element.js +1 -1
  22. package/layout/external-stylesheet.js +1 -1
  23. package/layout/flex-card.js +1 -1
  24. package/layout/flex-grid.js +1 -1
  25. package/layout/flex-row.js +1 -1
  26. package/layout/footer.js +1 -1
  27. package/layout/form-components/custom.js +1 -1
  28. package/layout/form-components/data-list.js +1 -1
  29. package/layout/form-components/floating-input.js +1 -1
  30. package/layout/form-components/form-all.js +1 -1
  31. package/layout/form-components/form.js +1 -1
  32. package/layout/form-components/image-picker.js +1 -1
  33. package/layout/form-components/picker.js +1 -1
  34. package/layout/form-components/radio.js +1 -1
  35. package/layout/form-components/radiogroup.js +1 -1
  36. package/layout/form-components/range.js +1 -1
  37. package/layout/free.js +1 -1
  38. package/layout/grid-new.js +1 -1
  39. package/layout/grid-switcher.js +1 -1
  40. package/layout/grid.js +1 -1
  41. package/layout/group.js +1 -1
  42. package/layout/header.js +1 -1
  43. package/layout/horizontal-scroller.js +1 -1
  44. package/layout/image-old.js +1 -1
  45. package/layout/image.js +1 -1
  46. package/layout/index.js +1 -1
  47. package/layout/label.js +1 -1
  48. package/layout/link.js +1 -1
  49. package/layout/list-OLD.js +1 -1
  50. package/layout/list.js +1 -1
  51. package/layout/meta-adder.js +1 -1
  52. package/layout/modal-2025.js +1 -1
  53. package/layout/modernwrap.js +1 -1
  54. package/layout/multiswitcher.js +1 -1
  55. package/layout/multiswitcherBeta.js +1 -1
  56. package/layout/nav-bar.js +1 -1
  57. package/layout/nav-factor/custom-div.js +1 -1
  58. package/layout/navBar-OLD.js +1 -1
  59. package/layout/new-flat-adder.js +1 -1
  60. package/layout/new-nav-bar.js +1 -1
  61. package/layout/offset-container.js +1 -1
  62. package/layout/polygon.js +1 -1
  63. package/layout/prerender.js +99 -10
  64. package/layout/progress.js +1 -1
  65. package/layout/row.js +1 -1
  66. package/layout/saved-new-nav-bar.js +1 -1
  67. package/layout/scroll-video.js +1 -1
  68. package/layout/side-bar.js +1 -1
  69. package/layout/side-nav-bar.js +1 -1
  70. package/layout/simple-bar.js +1 -1
  71. package/layout/slider-2025.js +1 -1
  72. package/layout/spacer.js +1 -1
  73. package/layout/stack.js +1 -1
  74. package/layout/styler.js +1 -1
  75. package/layout/svg.js +1 -1
  76. package/layout/switcher.js +1 -1
  77. package/layout/table.js +1 -1
  78. package/layout/text-field.js +1 -1
  79. package/layout/text.js +1 -1
  80. package/layout/ulist.js +1 -1
  81. package/layout/video.js +1 -1
  82. package/layout/without-new.js +1 -1
  83. package/layout/wrap.js +1 -1
  84. package/layout/zoom-card.js +1 -1
  85. package/lib/card-getter.js +1 -1
  86. package/lib/designer.js +1 -1
  87. package/lib/element-mapper.js +1 -1
  88. package/lib/keyframe-animation.js +1 -1
  89. package/lib/link-getter.js +1 -1
  90. package/lib/scroll-video.js +1 -1
  91. package/lib/stacker.js +1 -1
  92. package/lib/theme.js +1 -1
  93. package/lib/transform-anim.js +1 -1
  94. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/audio.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/base-2.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/base.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/box.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/button.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/cards.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
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.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
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.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
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.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/custom.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/footer.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
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.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
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.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/group.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/header.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
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.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/label.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
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.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
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.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/nav-bar.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
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.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -93,6 +93,15 @@ import path from "node:path";
93
93
  * @param {string} [opts.url="http://localhost/"] — Base URL for the jsdom
94
94
  * window. Affects `window.location`, relative-URL resolution, and the
95
95
  * `Document.URL` your code may read.
96
+ * @param {{ width?: number, height?: number }} [opts.viewport={width:390,height:844}]
97
+ * — Simulated viewport dimensions. Drives `window.innerWidth`,
98
+ * `window.innerHeight`, and the response of `window.matchMedia()`
99
+ * to viewport queries like `(min-width: 768px)`. Default is mobile
100
+ * (iPhone 12-ish: 390×844) so JS-driven responsive layouts (e.g.
101
+ * `Switcher({ breakpoints })`) emit the MOBILE variant during SSG.
102
+ * That's the "mobile-first" pattern — phones see the right layout
103
+ * immediately, desktop users see the mobile layout briefly until
104
+ * JS rehydrates with the desktop variant.
96
105
  * @param {(window: Window) => (void | Promise<void>)} opts.build —
97
106
  * Async function that runs inside the simulated browser. Receives the
98
107
  * jsdom `window` object. Should construct the page via Nodality
@@ -110,6 +119,7 @@ export async function prerender({
110
119
  locale,
111
120
  localStorageKey = "h7lang",
112
121
  url = "http://localhost/",
122
+ viewport = { width: 390, height: 844 },
113
123
  build,
114
124
  output,
115
125
  }) {
@@ -191,18 +201,58 @@ export async function prerender({
191
201
  disconnect() {}
192
202
  };
193
203
  }
194
- if (!window.matchMedia) {
195
- window.matchMedia = () => ({
196
- matches: false,
197
- media: "",
204
+ // Simulated viewport. jsdom's defaults are 1024×768 — we override
205
+ // with the caller-provided (or default mobile) dimensions so JS-
206
+ // driven responsive layouts pick the right variant during SSG.
207
+ //
208
+ // `innerWidth` / `innerHeight` are read by code like
209
+ // `Switcher.choose()` that compares `window.innerWidth` against
210
+ // each breakpoint's `at` value. They must be defined as values
211
+ // (not getters) so subsequent assignments don't throw.
212
+ const vw = (viewport && Number(viewport.width)) || 390;
213
+ const vh = (viewport && Number(viewport.height)) || 844;
214
+ try {
215
+ Object.defineProperty(window, "innerWidth", { value: vw, configurable: true, writable: true });
216
+ Object.defineProperty(window, "innerHeight", { value: vh, configurable: true, writable: true });
217
+ Object.defineProperty(window, "outerWidth", { value: vw, configurable: true, writable: true });
218
+ Object.defineProperty(window, "outerHeight", { value: vh, configurable: true, writable: true });
219
+ } catch {
220
+ // jsdom version that freezes these — fall back to direct assignment.
221
+ try { window.innerWidth = vw; window.innerHeight = vh; } catch {}
222
+ }
223
+
224
+ // Replace jsdom's matchMedia (which returns matches:false for every
225
+ // query) with a viewport-aware shim that resolves CSS `(min-width:
226
+ // N)` / `(max-width: N)` against the simulated width. This lets
227
+ // matchMedia-driven responsive code (and Nodality's Switcher
228
+ // matchMedia path) pick the right branch during SSG.
229
+ //
230
+ // We override unconditionally — jsdom's default is too permissive
231
+ // for our purposes since it answers `false` for every viewport
232
+ // query, defeating the mobile-first goal.
233
+ window.matchMedia = (query) => {
234
+ let matches = false;
235
+ if (typeof query === "string" && query.includes("width")) {
236
+ // Parse a single "(min-width: 768px)" or "(max-width: 768px)"
237
+ // clause. Multi-clause queries (commas, `and`) fall through to
238
+ // false — Nodality's breakpoint code doesn't emit those.
239
+ const min = query.match(/min-width:\s*(\d+)\s*px/i);
240
+ const max = query.match(/max-width:\s*(\d+)\s*px/i);
241
+ if (min && !max) matches = vw >= Number(min[1]);
242
+ else if (max && !min) matches = vw <= Number(max[1]);
243
+ // Both present (range) or other → leave as false.
244
+ }
245
+ return {
246
+ matches,
247
+ media: query || "",
198
248
  onchange: null,
199
249
  addListener() {},
200
250
  removeListener() {},
201
251
  addEventListener() {},
202
252
  removeEventListener() {},
203
253
  dispatchEvent() { return false; },
204
- });
205
- }
254
+ };
255
+ };
206
256
  // Some libraries probe these for code-splitting / analytics. Stub
207
257
  // them as harmless no-ops so the builder doesn't crash; the live
208
258
  // browser still uses the real implementations.
@@ -284,11 +334,50 @@ export async function prerender({
284
334
  // promise-based for full coverage.
285
335
  await new Promise((resolve) => setImmediate(resolve));
286
336
 
337
+ // ─── Hydration handoff ──────────────────────────────────────────
338
+ //
339
+ // The runtime <script> tags from the template still load in the
340
+ // live browser — they're how interactivity (dropdowns, animations,
341
+ // language switching) reaches the user. But Nodality's `render()`
342
+ // primitive APPENDS to the mount target rather than replacing it.
343
+ // That means without intervention, the browser would parse the
344
+ // prerendered DOM (visible), then app.js would run and append a
345
+ // SECOND copy of every section beneath it. The user sees the
346
+ // page rendered twice, stacked.
347
+ //
348
+ // Fix: inject a tiny inline `<script>` right BEFORE the first
349
+ // runtime module script. The inline script empties the mount
350
+ // container so app.js starts with a clean slate. Bots that don't
351
+ // execute JS still see the prerendered content (SEO + social
352
+ // preview win preserved). Users with JS see the prerendered
353
+ // content as instant-paint, then a sub-frame later the inline
354
+ // script clears mount and app.js rebuilds — visually a brief
355
+ // flicker, no duplication.
356
+ //
357
+ // Why not just have app.js clear mount itself: nodality has no
358
+ // hook for "before first render" and the page entry scripts in
359
+ // every consumer would each need the same boilerplate. Doing it
360
+ // here, once, keeps consumers untouched.
361
+ if (mount) {
362
+ const firstRuntimeScript = window.document.querySelector(
363
+ 'body script[type="module"][src], body script[src][type="module"]'
364
+ );
365
+ if (firstRuntimeScript) {
366
+ const clearScript = window.document.createElement("script");
367
+ // Inline (not type="module") so it executes synchronously,
368
+ // before any module scripts begin loading. Module scripts
369
+ // are always deferred, so the clear runs in the right order
370
+ // regardless of where it sits in the DOM relative to them.
371
+ clearScript.textContent =
372
+ `(function(){var m=document.querySelector(${JSON.stringify(mount)});if(m)m.innerHTML='';})();`;
373
+ firstRuntimeScript.parentNode.insertBefore(clearScript, firstRuntimeScript);
374
+ }
375
+ }
376
+
287
377
  // Serialize the full document. `dom.serialize()` returns
288
378
  // `<!DOCTYPE html><html>...</html>` including the template's
289
- // head + the now-populated body. The runtime <script> tags from
290
- // the template are preserved verbatim, so the live browser will
291
- // re-execute app.js and re-mount on top of the static DOM.
379
+ // head + the now-populated body PLUS the hydration-clear script
380
+ // we injected above.
292
381
  const rendered = dom.serialize();
293
382
 
294
383
  // Ensure the output directory exists. Writing to a path like
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
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.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
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.0.147
2
+ * nodality v1.0.149
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.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/styler.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/svg.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/table.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/text.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/ulist.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/video.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/wrap.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/lib/designer.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/lib/stacker.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/lib/theme.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.147
2
+ * nodality v1.0.149
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodality",
3
- "version": "1.0.147",
3
+ "version": "1.0.149",
4
4
  "description": "A lightweight library for declarative UI elements.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",