nodality 1.0.152 → 1.0.153

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 (95) 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-site.js +85 -24
  64. package/layout/prerender.js +1 -1
  65. package/layout/progress.js +1 -1
  66. package/layout/row.js +1 -1
  67. package/layout/saved-new-nav-bar.js +1 -1
  68. package/layout/scroll-video.js +1 -1
  69. package/layout/side-bar.js +1 -1
  70. package/layout/side-nav-bar.js +1 -1
  71. package/layout/simple-bar.js +1 -1
  72. package/layout/slider-2025.js +1 -1
  73. package/layout/spacer.js +1 -1
  74. package/layout/stack.js +1 -1
  75. package/layout/styler.js +1 -1
  76. package/layout/svg.js +1 -1
  77. package/layout/switcher.js +1 -1
  78. package/layout/table.js +1 -1
  79. package/layout/text-field.js +1 -1
  80. package/layout/text.js +1 -1
  81. package/layout/ulist.js +1 -1
  82. package/layout/video.js +1 -1
  83. package/layout/without-new.js +1 -1
  84. package/layout/wrap.js +1 -1
  85. package/layout/zoom-card.js +1 -1
  86. package/lib/card-getter.js +1 -1
  87. package/lib/designer.js +1 -1
  88. package/lib/element-mapper.js +1 -1
  89. package/lib/keyframe-animation.js +1 -1
  90. package/lib/link-getter.js +1 -1
  91. package/lib/scroll-video.js +1 -1
  92. package/lib/stacker.js +1 -1
  93. package/lib/theme.js +1 -1
  94. package/lib/transform-anim.js +1 -1
  95. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -96,11 +96,15 @@ const DEFAULT_ASSET_PREFIXES = [
96
96
  * the template HTML + entry .js files. Output
97
97
  * files are written under it (default locale
98
98
  * at the root, others under /<locale>/).
99
- * @param {string} config.defaultLocale — The locale code whose pages live at the
99
+ * @param {string} [config.defaultLocale] — The locale code whose pages live at the
100
100
  * root of uploadDir. All other locales get a
101
- * same-named subdir.
102
- * @param {string[]} config.locales — All locale codes to render. Must include
103
- * `defaultLocale`.
101
+ * same-named subdir. Optional — omit for a
102
+ * single-locale site with no locale tagging.
103
+ * @param {string[]} [config.locales] — All locale codes to render. Must include
104
+ * `defaultLocale` (if both given). Defaults
105
+ * to `[defaultLocale]` when only the default
106
+ * is set; defaults to a single untagged
107
+ * build when neither is set.
104
108
  * @param {Array<{html:string,entry:string}>} config.pages
105
109
  * — Each page's public HTML file (used as
106
110
  * template) and the JS entry script that
@@ -121,19 +125,39 @@ export async function prerenderSite(config) {
121
125
 
122
126
  // Child mode? Render exactly one locale and exit.
123
127
  const childLocale = process.env[ENV_LOCALE];
124
- if (childLocale) {
125
- return runChild(config, childLocale);
128
+ if (childLocale !== undefined) {
129
+ // The env var carries a string; map the literal "null" sentinel
130
+ // back to a real null so single-locale paths work in the child.
131
+ const locale = childLocale === "__none__" ? null : childLocale;
132
+ return runChild(config, locale);
126
133
  }
127
134
 
128
- // Parent mode fan out one subprocess per locale, sequentially
129
- // (parallel would scramble console output and risk thrashing CPU).
135
+ // Single-locale (or unspecified) fast path: skip subprocess fanout.
136
+ // There's no ESM-cache-leak risk to guard against because only one
137
+ // locale will run in this process. Sitemap/hreflang are also no-ops
138
+ // when there's only one locale.
130
139
  const startedAt = Date.now();
140
+ const isMulti = config.locales.length > 1;
141
+
142
+ if (!isMulti) {
143
+ const locale = config.locales[0];
144
+ console.log(`🌍 Prerendering ${config.pages.length} page(s)${locale ? ` (${locale})` : ""}…`);
145
+ console.log();
146
+ await runChild(config, locale);
147
+ const elapsed = ((Date.now() - startedAt) / 1000).toFixed(1);
148
+ console.log(`✅ Prerender done in ${elapsed}s — ${config.pages.length} page(s)`);
149
+ return;
150
+ }
151
+
152
+ // Multi-locale: fan out one subprocess per locale, sequentially
153
+ // (parallel would scramble console output and risk thrashing CPU).
131
154
  console.log(`🌍 Prerendering ${config.locales.length} locales × ${config.pages.length} pages…`);
132
155
  console.log();
133
156
 
134
157
  let failures = 0;
135
158
  for (const locale of config.locales) {
136
- console.log(`── ${locale} ${"─".repeat(60 - locale.length - 3)}`);
159
+ const label = locale ?? "(default)";
160
+ console.log(`── ${label} ${"─".repeat(60 - String(label).length - 3)}`);
137
161
  const ok = await runLocaleSubprocess(locale);
138
162
  if (!ok) failures++;
139
163
  console.log();
@@ -153,16 +177,11 @@ export async function prerenderSite(config) {
153
177
  }
154
178
 
155
179
  function validateConfig(config) {
156
- const required = ["origin", "uploadDir", "defaultLocale", "locales", "pages"];
180
+ // Hard requirements no sensible defaults possible.
181
+ const required = ["origin", "uploadDir", "pages"];
157
182
  for (const k of required) {
158
183
  if (!config[k]) throw new Error(`prerenderSite: config.${k} is required`);
159
184
  }
160
- if (!Array.isArray(config.locales) || config.locales.length === 0) {
161
- throw new Error("prerenderSite: config.locales must be a non-empty array");
162
- }
163
- if (!config.locales.includes(config.defaultLocale)) {
164
- throw new Error(`prerenderSite: config.defaultLocale "${config.defaultLocale}" not in config.locales`);
165
- }
166
185
  if (!Array.isArray(config.pages) || config.pages.length === 0) {
167
186
  throw new Error("prerenderSite: config.pages must be a non-empty array");
168
187
  }
@@ -171,6 +190,32 @@ function validateConfig(config) {
171
190
  throw new Error("prerenderSite: each page needs { html, entry }");
172
191
  }
173
192
  }
193
+
194
+ // Soft defaults for the locale config — a single-locale site
195
+ // doesn't need to declare anything beyond the implicit "default".
196
+ // We mutate config here so the rest of the file can assume both
197
+ // keys are populated.
198
+ if (!config.defaultLocale && !config.locales) {
199
+ // Fully unspecified — single-locale build, no locale tagging.
200
+ // Use a sentinel `null` so subsequent code can skip <html lang>,
201
+ // hreflang, and localStorage injection.
202
+ config.defaultLocale = null;
203
+ config.locales = [null];
204
+ } else if (!config.locales) {
205
+ // Default declared but no list given — single-locale build at
206
+ // the root with that default locale's <html lang>.
207
+ config.locales = [config.defaultLocale];
208
+ } else if (!Array.isArray(config.locales) || config.locales.length === 0) {
209
+ throw new Error("prerenderSite: config.locales must be a non-empty array");
210
+ } else if (!config.defaultLocale) {
211
+ // Locales given but no default — assume the first entry is the
212
+ // one whose pages live at the root.
213
+ config.defaultLocale = config.locales[0];
214
+ }
215
+
216
+ if (config.defaultLocale && !config.locales.includes(config.defaultLocale)) {
217
+ throw new Error(`prerenderSite: config.defaultLocale "${config.defaultLocale}" not in config.locales`);
218
+ }
174
219
  }
175
220
 
176
221
  /**
@@ -188,9 +233,12 @@ function runLocaleSubprocess(locale) {
188
233
  resolve(false);
189
234
  return;
190
235
  }
236
+ // Encode null locale as a sentinel string so it survives the env
237
+ // round-trip (env vars are always strings).
238
+ const localeStr = locale === null ? "__none__" : locale;
191
239
  const child = spawn(process.execPath, [entry], {
192
240
  cwd: process.cwd(),
193
- env: { ...process.env, [ENV_LOCALE]: locale },
241
+ env: { ...process.env, [ENV_LOCALE]: localeStr },
194
242
  stdio: "inherit",
195
243
  });
196
244
  child.on("exit", (code) => resolve(code === 0));
@@ -218,7 +266,9 @@ async function runChild(config, locale) {
218
266
  localStorageKey = "h7lang",
219
267
  } = config;
220
268
 
221
- const isSubdir = locale !== defaultLocale;
269
+ // A null locale (single-locale, untagged) always renders to the
270
+ // root. Any other locale goes to root only if it equals the default.
271
+ const isSubdir = locale !== null && locale !== defaultLocale;
222
272
  const localeDir = isSubdir ? path.join(uploadDir, locale) : uploadDir;
223
273
  await fs.mkdir(localeDir, { recursive: true });
224
274
 
@@ -255,17 +305,27 @@ async function runChild(config, locale) {
255
305
  process.stdout.write(` ${page.html.padEnd(22)} `);
256
306
 
257
307
  try {
308
+ // Build the prerender call. Locale-related options are
309
+ // skipped when this is a single-locale-untagged build
310
+ // (locale === null) so the static output has no <html lang>,
311
+ // no canonical, no hreflang, no localStorage seed. The
312
+ // consumer's site looks like a vanilla single-page build.
313
+ const isLocaleAware = locale !== null;
258
314
  const result = await prerender({
259
315
  template: tmplPath,
260
316
  output: outPath,
261
317
  mount,
262
- locale,
318
+ locale: isLocaleAware ? locale : undefined,
263
319
  localStorageKey,
264
320
  viewport,
265
321
  url: urlFor(config, locale, page.html),
266
- htmlLang: locale,
267
- canonical: urlFor(config, locale, page.html),
268
- alternates: alternatesFor(config, page.html),
322
+ htmlLang: isLocaleAware ? locale : undefined,
323
+ canonical: isLocaleAware && config.locales.length > 1
324
+ ? urlFor(config, locale, page.html)
325
+ : undefined,
326
+ alternates: isLocaleAware && config.locales.length > 1
327
+ ? alternatesFor(config, page.html)
328
+ : undefined,
269
329
  build: async () => {
270
330
  const importUrl = `${pathToFileURL(entryPath).href}?t=${stamp}-${page.entry}`;
271
331
  await import(importUrl);
@@ -331,7 +391,8 @@ async function buildCleanTemplate(htmlPath, isSubdir, mount) {
331
391
 
332
392
  /** URL for a (locale, page) pair under this site's origin. */
333
393
  function urlFor(config, locale, page) {
334
- const slash = locale === config.defaultLocale ? "" : `${locale}/`;
394
+ // Null locale (untagged) and the default locale both live at root.
395
+ const slash = (locale === null || locale === config.defaultLocale) ? "" : `${locale}/`;
335
396
  const tail = page === "index.html" ? slash : `${slash}${page}`;
336
397
  return `${config.origin}/${tail}`;
337
398
  }
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
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.152
2
+ * nodality v1.0.153
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.0.152
2
+ * nodality v1.0.153
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.152",
3
+ "version": "1.0.153",
4
4
  "description": "A lightweight library for declarative UI elements.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",