meno-core 1.0.53 → 1.0.54

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 (387) hide show
  1. package/.claude/settings.local.json +1 -3
  2. package/bin/cli.ts +48 -57
  3. package/build-astro.ts +131 -113
  4. package/build-next.ts +109 -96
  5. package/build-static.test.ts +39 -10
  6. package/build-static.ts +120 -122
  7. package/dist/bin/cli.js +34 -38
  8. package/dist/bin/cli.js.map +2 -2
  9. package/dist/build-static.js +12 -11
  10. package/dist/chunks/chunk-2AR55GYH.js +42 -0
  11. package/dist/chunks/chunk-2AR55GYH.js.map +7 -0
  12. package/dist/chunks/{chunk-IGYR22T6.js → chunk-2FN4UOVO.js} +512 -239
  13. package/dist/chunks/chunk-2FN4UOVO.js.map +7 -0
  14. package/dist/chunks/chunk-3XER4E5W.js +168 -0
  15. package/dist/chunks/chunk-3XER4E5W.js.map +7 -0
  16. package/dist/chunks/{chunk-X754AHS5.js → chunk-5ETZFREW.js} +9 -12
  17. package/dist/chunks/chunk-5ETZFREW.js.map +7 -0
  18. package/dist/chunks/{chunk-2MHDV5BF.js → chunk-7E4IF5L7.js} +15 -21
  19. package/dist/chunks/chunk-7E4IF5L7.js.map +7 -0
  20. package/dist/chunks/{chunk-JGWFTO6P.js → chunk-7HWQUVTU.js} +1578 -1349
  21. package/dist/chunks/chunk-7HWQUVTU.js.map +7 -0
  22. package/dist/chunks/{chunk-O3NAGJP4.js → chunk-AE3QK5QW.js} +110 -21
  23. package/dist/chunks/chunk-AE3QK5QW.js.map +7 -0
  24. package/dist/chunks/{chunk-GZHGVVW3.js → chunk-F6KTJYGV.js} +7 -7
  25. package/dist/chunks/chunk-F6KTJYGV.js.map +7 -0
  26. package/dist/chunks/{chunk-WQFG7PAH.js → chunk-FZITJSSS.js} +2 -6
  27. package/dist/chunks/chunk-FZITJSSS.js.map +7 -0
  28. package/dist/chunks/{chunk-QB2LNO4W.js → chunk-GSYYA5GX.js} +2 -2
  29. package/dist/chunks/chunk-GSYYA5GX.js.map +7 -0
  30. package/dist/chunks/{chunk-YBLHKYFF.js → chunk-HIZMY3EP.js} +1 -1
  31. package/dist/chunks/chunk-HIZMY3EP.js.map +7 -0
  32. package/dist/chunks/{chunk-AZQYF6KE.js → chunk-I2WEGYA7.js} +41 -176
  33. package/dist/chunks/chunk-I2WEGYA7.js.map +7 -0
  34. package/dist/chunks/{chunk-I7YIGZXT.js → chunk-JNO3CNLJ.js} +6 -9
  35. package/dist/chunks/chunk-JNO3CNLJ.js.map +7 -0
  36. package/dist/chunks/{chunk-UB44F4Z2.js → chunk-NVRBTSQG.js} +2 -4
  37. package/dist/chunks/chunk-NVRBTSQG.js.map +7 -0
  38. package/dist/chunks/{chunk-JGP5A3Y5.js → chunk-Q4OBWKXG.js} +40 -33
  39. package/dist/chunks/chunk-Q4OBWKXG.js.map +7 -0
  40. package/dist/chunks/{chunk-R6XHAFBF.js → chunk-QTE32Y53.js} +250 -242
  41. package/dist/chunks/chunk-QTE32Y53.js.map +7 -0
  42. package/dist/chunks/{chunk-H3GJ4H2U.js → chunk-STDY3OVM.js} +214 -85
  43. package/dist/chunks/chunk-STDY3OVM.js.map +7 -0
  44. package/dist/chunks/configService-PRJZF7Y6.js +14 -0
  45. package/dist/chunks/{constants-STK2YBIW.js → constants-KIQEYMAM.js} +2 -2
  46. package/dist/chunks/{fs-JGINUXGL.js → fs-ZI5JEU7V.js} +2 -2
  47. package/dist/entries/server-router.js +14 -19
  48. package/dist/entries/server-router.js.map +2 -2
  49. package/dist/lib/client/index.js +638 -332
  50. package/dist/lib/client/index.js.map +2 -2
  51. package/dist/lib/server/index.js +177 -235
  52. package/dist/lib/server/index.js.map +2 -2
  53. package/dist/lib/shared/index.js +80 -44
  54. package/dist/lib/shared/index.js.map +2 -2
  55. package/dist/lib/shared/richtext/index.js +1 -1
  56. package/dist/lib/test-utils/index.js +38 -60
  57. package/dist/lib/test-utils/index.js.map +2 -2
  58. package/entries/client-router.tsx +10 -8
  59. package/entries/server-router.tsx +1 -7
  60. package/lib/client/ClientInitializer.ts +8 -8
  61. package/lib/client/ErrorBoundary.test.tsx +146 -143
  62. package/lib/client/ErrorBoundary.tsx +175 -127
  63. package/lib/client/componentRegistry.test.ts +96 -108
  64. package/lib/client/componentRegistry.ts +1 -2
  65. package/lib/client/contexts/ThemeContext.tsx +3 -2
  66. package/lib/client/core/ComponentBuilder.test.ts +513 -560
  67. package/lib/client/core/ComponentBuilder.ts +318 -146
  68. package/lib/client/core/ComponentRenderer.test.tsx +1 -2
  69. package/lib/client/core/ComponentRenderer.tsx +46 -33
  70. package/lib/client/core/builders/embedBuilder.ts +241 -53
  71. package/lib/client/core/builders/linkBuilder.ts +71 -44
  72. package/lib/client/core/builders/linkNodeBuilder.ts +78 -53
  73. package/lib/client/core/builders/listBuilder.ts +115 -86
  74. package/lib/client/core/builders/localeListBuilder.ts +95 -60
  75. package/lib/client/core/builders/types.ts +5 -5
  76. package/lib/client/core/cmsTemplateProcessor.ts +7 -7
  77. package/lib/client/elementRegistry.ts +3 -3
  78. package/lib/client/fontFamiliesService.test.ts +2 -10
  79. package/lib/client/fontFamiliesService.ts +3 -3
  80. package/lib/client/hmr/HMRManager.tsx +8 -0
  81. package/lib/client/hmrCssReload.ts +14 -8
  82. package/lib/client/hmrWebSocket.ts +9 -14
  83. package/lib/client/hooks/useColorVariables.test.ts +21 -21
  84. package/lib/client/hooks/useColorVariables.ts +12 -10
  85. package/lib/client/hooks/usePropertyAutocomplete.ts +3 -5
  86. package/lib/client/hooks/useVariables.ts +4 -4
  87. package/lib/client/hydration/HydrationUtils.test.ts +24 -25
  88. package/lib/client/hydration/HydrationUtils.ts +3 -4
  89. package/lib/client/i18nConfigService.test.ts +2 -7
  90. package/lib/client/i18nConfigService.ts +2 -2
  91. package/lib/client/meno-filter/MenoFilter.test.ts +19 -21
  92. package/lib/client/meno-filter/MenoFilter.ts +5 -9
  93. package/lib/client/meno-filter/bindings.ts +15 -40
  94. package/lib/client/meno-filter/init.ts +1 -1
  95. package/lib/client/meno-filter/renderer.ts +23 -29
  96. package/lib/client/meno-filter/script.generated.ts +1 -3
  97. package/lib/client/meno-filter/ui.ts +3 -5
  98. package/lib/client/meno-filter/updates.ts +15 -21
  99. package/lib/client/navigation.test.ts +159 -159
  100. package/lib/client/navigation.ts +0 -1
  101. package/lib/client/responsiveStyleResolver.test.ts +230 -228
  102. package/lib/client/responsiveStyleResolver.ts +13 -16
  103. package/lib/client/routing/RouteLoader.test.ts +23 -24
  104. package/lib/client/routing/RouteLoader.ts +22 -35
  105. package/lib/client/routing/Router.tsx +31 -3
  106. package/lib/client/scripts/ScriptExecutor.test.ts +157 -158
  107. package/lib/client/scripts/ScriptExecutor.ts +15 -33
  108. package/lib/client/services/PrefetchService.test.ts +2 -2
  109. package/lib/client/services/PrefetchService.ts +10 -24
  110. package/lib/client/styleProcessor.test.ts +9 -9
  111. package/lib/client/styleProcessor.ts +18 -15
  112. package/lib/client/styles/StyleInjector.test.ts +122 -115
  113. package/lib/client/styles/StyleInjector.ts +9 -6
  114. package/lib/client/styles/UtilityClassCollector.ts +19 -26
  115. package/lib/client/styles/cspNonce.test.ts +2 -5
  116. package/lib/client/templateEngine.test.ts +554 -482
  117. package/lib/client/templateEngine.ts +200 -64
  118. package/lib/client/theme.ts +0 -1
  119. package/lib/client/utils/toast.ts +0 -1
  120. package/lib/server/__integration__/api-routes.test.ts +8 -4
  121. package/lib/server/__integration__/cms-integration.test.ts +1 -4
  122. package/lib/server/__integration__/server-lifecycle.test.ts +2 -5
  123. package/lib/server/__integration__/ssr-rendering.test.ts +47 -37
  124. package/lib/server/__integration__/static-assets.test.ts +1 -1
  125. package/lib/server/__integration__/test-helpers.ts +84 -70
  126. package/lib/server/ab/generateFunctions.ts +12 -10
  127. package/lib/server/astro/cmsPageEmitter.ts +23 -38
  128. package/lib/server/astro/componentEmitter.ts +25 -36
  129. package/lib/server/astro/cssCollector.ts +10 -26
  130. package/lib/server/astro/nodeToAstro.test.ts +1750 -30
  131. package/lib/server/astro/nodeToAstro.ts +198 -187
  132. package/lib/server/astro/normalizeOrphanTemplateProps.test.ts +105 -109
  133. package/lib/server/astro/normalizeOrphanTemplateProps.ts +4 -12
  134. package/lib/server/astro/pageEmitter.ts +9 -13
  135. package/lib/server/astro/tailwindMapper.test.ts +10 -37
  136. package/lib/server/astro/tailwindMapper.ts +33 -40
  137. package/lib/server/astro/templateTransformer.ts +14 -17
  138. package/lib/server/createServer.ts +5 -17
  139. package/lib/server/cssGenerator.test.ts +35 -44
  140. package/lib/server/cssGenerator.ts +6 -17
  141. package/lib/server/fileWatcher.test.ts +124 -10
  142. package/lib/server/fileWatcher.ts +124 -118
  143. package/lib/server/index.ts +7 -1
  144. package/lib/server/jsonLoader.test.ts +39 -2
  145. package/lib/server/jsonLoader.ts +33 -31
  146. package/lib/server/middleware/cors.test.ts +20 -20
  147. package/lib/server/middleware/cors.ts +28 -4
  148. package/lib/server/middleware/errorHandler.test.ts +5 -3
  149. package/lib/server/middleware/errorHandler.ts +3 -8
  150. package/lib/server/middleware/index.ts +0 -1
  151. package/lib/server/middleware/logger.test.ts +7 -5
  152. package/lib/server/middleware/logger.ts +10 -22
  153. package/lib/server/pageCache.test.ts +76 -77
  154. package/lib/server/pageCache.ts +0 -1
  155. package/lib/server/projectContext.ts +4 -3
  156. package/lib/server/providers/fileSystemCMSProvider.test.ts +124 -95
  157. package/lib/server/providers/fileSystemCMSProvider.ts +35 -20
  158. package/lib/server/providers/fileSystemPageProvider.test.ts +84 -0
  159. package/lib/server/providers/fileSystemPageProvider.ts +31 -12
  160. package/lib/server/routes/api/cms.test.ts +26 -14
  161. package/lib/server/routes/api/cms.ts +9 -14
  162. package/lib/server/routes/api/components.ts +30 -34
  163. package/lib/server/routes/api/config.ts +0 -1
  164. package/lib/server/routes/api/core-routes.ts +47 -74
  165. package/lib/server/routes/api/functions.ts +8 -16
  166. package/lib/server/routes/api/index.ts +3 -6
  167. package/lib/server/routes/api/pages.ts +8 -11
  168. package/lib/server/routes/api/shared.test.ts +1 -1
  169. package/lib/server/routes/api/shared.ts +12 -9
  170. package/lib/server/routes/api/variables.test.ts +1 -3
  171. package/lib/server/routes/api/variables.ts +1 -1
  172. package/lib/server/routes/index.ts +23 -26
  173. package/lib/server/routes/pages.ts +34 -29
  174. package/lib/server/routes/static.ts +16 -4
  175. package/lib/server/runtime/bundler.ts +47 -32
  176. package/lib/server/runtime/fs.ts +3 -13
  177. package/lib/server/runtime/httpServer.ts +5 -9
  178. package/lib/server/services/ColorService.ts +32 -27
  179. package/lib/server/services/EnumService.test.ts +2 -6
  180. package/lib/server/services/EnumService.ts +7 -2
  181. package/lib/server/services/VariableService.test.ts +1 -5
  182. package/lib/server/services/VariableService.ts +6 -1
  183. package/lib/server/services/cmsService.test.ts +116 -78
  184. package/lib/server/services/cmsService.ts +24 -54
  185. package/lib/server/services/componentService.test.ts +122 -36
  186. package/lib/server/services/componentService.ts +54 -38
  187. package/lib/server/services/configService.test.ts +9 -31
  188. package/lib/server/services/configService.ts +20 -27
  189. package/lib/server/services/fileWatcherService.ts +40 -6
  190. package/lib/server/services/index.ts +0 -1
  191. package/lib/server/services/pageService.test.ts +1 -3
  192. package/lib/server/services/pageService.ts +14 -13
  193. package/lib/server/ssr/attributeBuilder.ts +16 -6
  194. package/lib/server/ssr/buildErrorOverlay.ts +11 -12
  195. package/lib/server/ssr/clientDataInjector.ts +7 -21
  196. package/lib/server/ssr/cmsSSRProcessor.ts +3 -6
  197. package/lib/server/ssr/cssCollector.ts +1 -1
  198. package/lib/server/ssr/errorOverlay.test.ts +1 -1
  199. package/lib/server/ssr/errorOverlay.ts +3 -9
  200. package/lib/server/ssr/htmlGenerator.nonce.test.ts +3 -9
  201. package/lib/server/ssr/htmlGenerator.test.ts +120 -43
  202. package/lib/server/ssr/htmlGenerator.ts +120 -85
  203. package/lib/server/ssr/imageMetadata.test.ts +3 -1
  204. package/lib/server/ssr/imageMetadata.ts +25 -19
  205. package/lib/server/ssr/jsCollector.test.ts +3 -13
  206. package/lib/server/ssr/jsCollector.ts +3 -8
  207. package/lib/server/ssr/liveReloadIntegration.test.ts +69 -28
  208. package/lib/server/ssr/metaTagGenerator.ts +2 -2
  209. package/lib/server/ssr/ssrRenderer.branches.test.ts +1103 -0
  210. package/lib/server/ssr/ssrRenderer.test.ts +196 -246
  211. package/lib/server/ssr/ssrRenderer.ts +609 -225
  212. package/lib/server/ssrRenderer.test.ts +1044 -950
  213. package/lib/server/utils/jsonLineMapper.test.ts +28 -28
  214. package/lib/server/utils/jsonLineMapper.ts +1 -1
  215. package/lib/server/validateStyleCoverage.ts +18 -20
  216. package/lib/server/webflow/buildWebflow.ts +41 -53
  217. package/lib/server/webflow/nodeToWebflow.test.ts +150 -218
  218. package/lib/server/webflow/nodeToWebflow.ts +195 -258
  219. package/lib/server/webflow/styleMapper.test.ts +15 -56
  220. package/lib/server/webflow/styleMapper.ts +33 -41
  221. package/lib/server/webflow/types.ts +1 -8
  222. package/lib/server/websocketManager.ts +16 -19
  223. package/lib/shared/attributeNodeUtils.test.ts +15 -15
  224. package/lib/shared/attributeNodeUtils.ts +5 -12
  225. package/lib/shared/breakpoints.ts +4 -11
  226. package/lib/shared/cmsQueryParser.test.ts +50 -42
  227. package/lib/shared/cmsQueryParser.ts +49 -31
  228. package/lib/shared/colorVariableUtils.test.ts +5 -5
  229. package/lib/shared/colorVariableUtils.ts +3 -8
  230. package/lib/shared/componentRefs.ts +1 -5
  231. package/lib/shared/constants.test.ts +3 -3
  232. package/lib/shared/constants.ts +4 -8
  233. package/lib/shared/cssGeneration.test.ts +262 -144
  234. package/lib/shared/cssGeneration.ts +189 -516
  235. package/lib/shared/cssNamedColors.ts +152 -30
  236. package/lib/shared/cssProperties.test.ts +5 -6
  237. package/lib/shared/cssProperties.ts +296 -112
  238. package/lib/shared/elementClassName.test.ts +109 -109
  239. package/lib/shared/elementClassName.ts +1 -1
  240. package/lib/shared/elementUtils.ts +12 -16
  241. package/lib/shared/errorLogger.ts +2 -10
  242. package/lib/shared/errors.test.ts +2 -13
  243. package/lib/shared/errors.ts +2 -8
  244. package/lib/shared/expressionEvaluator.test.ts +119 -0
  245. package/lib/shared/expressionEvaluator.ts +43 -24
  246. package/lib/shared/fontLoader.test.ts +19 -5
  247. package/lib/shared/friendlyError.ts +2 -3
  248. package/lib/shared/gradientUtils.test.ts +1 -5
  249. package/lib/shared/gradientUtils.ts +2 -6
  250. package/lib/shared/hrefRefs.ts +2 -10
  251. package/lib/shared/i18n.test.ts +1 -1
  252. package/lib/shared/i18n.ts +13 -34
  253. package/lib/shared/index.ts +4 -0
  254. package/lib/shared/inlineSvgStyleRules.ts +2 -4
  255. package/lib/shared/interactiveStyleMappings.test.ts +11 -33
  256. package/lib/shared/interactiveStyleMappings.ts +9 -16
  257. package/lib/shared/interactiveStyles.test.ts +165 -188
  258. package/lib/shared/interfaces/contentProvider.ts +1 -1
  259. package/lib/shared/itemTemplateUtils.test.ts +6 -12
  260. package/lib/shared/itemTemplateUtils.ts +19 -35
  261. package/lib/shared/jsonRepair.ts +8 -2
  262. package/lib/shared/libraryLoader.test.ts +15 -49
  263. package/lib/shared/libraryLoader.ts +7 -22
  264. package/lib/shared/netlifyLocale404.test.ts +179 -0
  265. package/lib/shared/netlifyLocale404.ts +110 -0
  266. package/lib/shared/nodeUtils.test.ts +24 -16
  267. package/lib/shared/nodeUtils.ts +49 -19
  268. package/lib/shared/pathArrayUtils.test.ts +1 -2
  269. package/lib/shared/pathArrayUtils.ts +1 -1
  270. package/lib/shared/pathSecurity.ts +1 -1
  271. package/lib/shared/pathUtils.test.ts +4 -6
  272. package/lib/shared/pathUtils.ts +42 -48
  273. package/lib/shared/paths/Path.test.ts +2 -2
  274. package/lib/shared/paths/Path.ts +0 -1
  275. package/lib/shared/paths/PathConverter.test.ts +1 -1
  276. package/lib/shared/paths/PathConverter.ts +14 -17
  277. package/lib/shared/paths/PathUtils.ts +9 -10
  278. package/lib/shared/paths/PathValidator.test.ts +2 -15
  279. package/lib/shared/paths/PathValidator.ts +11 -9
  280. package/lib/shared/paths/index.ts +1 -2
  281. package/lib/shared/propResolver.test.ts +240 -244
  282. package/lib/shared/propResolver.ts +14 -25
  283. package/lib/shared/pxToRem.test.ts +7 -6
  284. package/lib/shared/pxToRem.ts +2 -5
  285. package/lib/shared/registry/BaseNodeTypeRegistry.test.ts +9 -5
  286. package/lib/shared/registry/ClientRegistry.ts +0 -1
  287. package/lib/shared/registry/ComponentRegistry.test.ts +43 -29
  288. package/lib/shared/registry/ComponentRegistry.ts +9 -11
  289. package/lib/shared/registry/NodeTypeDefinition.ts +15 -8
  290. package/lib/shared/registry/RegistryManager.ts +1 -2
  291. package/lib/shared/registry/SSRRegistry.ts +0 -1
  292. package/lib/shared/registry/createNodeType.ts +7 -9
  293. package/lib/shared/registry/defineNodeType.ts +2 -6
  294. package/lib/shared/registry/index.ts +0 -1
  295. package/lib/shared/registry/nodeTypes/ComponentInstanceNodeType.ts +14 -15
  296. package/lib/shared/registry/nodeTypes/EmbedNodeType.ts +18 -11
  297. package/lib/shared/registry/nodeTypes/HtmlNodeType.ts +47 -18
  298. package/lib/shared/registry/nodeTypes/LinkNodeType.ts +21 -19
  299. package/lib/shared/registry/nodeTypes/ListNodeType.ts +78 -74
  300. package/lib/shared/registry/nodeTypes/LocaleListNodeType.ts +27 -21
  301. package/lib/shared/registry/nodeTypes/SlotMarkerType.ts +6 -7
  302. package/lib/shared/registry/nodeTypes/index.ts +10 -2
  303. package/lib/shared/responsiveScaling.test.ts +15 -31
  304. package/lib/shared/responsiveScaling.ts +55 -37
  305. package/lib/shared/responsiveStyleUtils.ts +11 -13
  306. package/lib/shared/richtext/htmlToTiptap.test.ts +23 -14
  307. package/lib/shared/richtext/htmlToTiptap.ts +1 -3
  308. package/lib/shared/richtext/tiptapToHtml.test.ts +5 -6
  309. package/lib/shared/richtext/types.ts +1 -8
  310. package/lib/shared/slugTranslator.test.ts +13 -13
  311. package/lib/shared/slugTranslator.ts +12 -16
  312. package/lib/shared/slugify.ts +9 -15
  313. package/lib/shared/styleNodeUtils.test.ts +8 -8
  314. package/lib/shared/styleNodeUtils.ts +5 -10
  315. package/lib/shared/styleUtils.test.ts +87 -61
  316. package/lib/shared/styleUtils.ts +5 -6
  317. package/lib/shared/themeDefaults.test.ts +11 -11
  318. package/lib/shared/themeDefaults.ts +3 -4
  319. package/lib/shared/tree/PathBuilder.test.ts +62 -138
  320. package/lib/shared/tree/PathBuilder.ts +49 -39
  321. package/lib/shared/treePathUtils.test.ts +2 -10
  322. package/lib/shared/treePathUtils.ts +54 -59
  323. package/lib/shared/types/api.ts +1 -2
  324. package/lib/shared/types/cms.ts +25 -21
  325. package/lib/shared/types/comment.ts +49 -16
  326. package/lib/shared/types/components.ts +27 -25
  327. package/lib/shared/types/errors.test.ts +1 -6
  328. package/lib/shared/types/errors.ts +3 -7
  329. package/lib/shared/types/experiments.ts +28 -28
  330. package/lib/shared/types/index.ts +2 -2
  331. package/lib/shared/types/styles.ts +0 -1
  332. package/lib/shared/types/variables.test.ts +4 -13
  333. package/lib/shared/types/variables.ts +48 -27
  334. package/lib/shared/types.ts +1 -2
  335. package/lib/shared/utilityClassConfig.ts +648 -321
  336. package/lib/shared/utilityClassMapper.test.ts +203 -92
  337. package/lib/shared/utilityClassMapper.ts +188 -246
  338. package/lib/shared/utilityClassNames.ts +326 -0
  339. package/lib/shared/utils.test.ts +2 -10
  340. package/lib/shared/utils.ts +19 -10
  341. package/lib/shared/validation/cmsValidators.ts +2 -1
  342. package/lib/shared/validation/commentValidators.test.ts +53 -0
  343. package/lib/shared/validation/commentValidators.ts +12 -1
  344. package/lib/shared/validation/propValidator.test.ts +18 -20
  345. package/lib/shared/validation/propValidator.ts +12 -17
  346. package/lib/shared/validation/schemas.test.ts +24 -33
  347. package/lib/shared/validation/schemas.ts +469 -344
  348. package/lib/shared/validation/validators.test.ts +1 -6
  349. package/lib/shared/validation/validators.ts +89 -68
  350. package/lib/shared/viewportUnits.integration.test.ts +14 -10
  351. package/lib/shared/viewportUnits.test.ts +11 -23
  352. package/lib/test-utils/dom-setup.ts +1 -1
  353. package/lib/test-utils/factories/ConsoleMockFactory.ts +3 -7
  354. package/lib/test-utils/factories/DomMockFactory.ts +7 -19
  355. package/lib/test-utils/factories/EventMockFactory.ts +7 -13
  356. package/lib/test-utils/factories/FetchMockFactory.ts +39 -57
  357. package/lib/test-utils/factories/ServerMockFactory.ts +5 -9
  358. package/lib/test-utils/factories/StoreMockFactory.ts +14 -25
  359. package/lib/test-utils/fixtures.ts +45 -45
  360. package/lib/test-utils/helpers/asyncHelpers.test.ts +15 -18
  361. package/lib/test-utils/helpers/asyncHelpers.ts +11 -20
  362. package/lib/test-utils/helpers.ts +1 -5
  363. package/lib/test-utils/index.ts +0 -4
  364. package/lib/test-utils/mockFactories.ts +12 -18
  365. package/lib/test-utils/mocks.ts +4 -2
  366. package/package.json +1 -1
  367. package/scripts/build-meno-filter.ts +1 -4
  368. package/vite.config.ts +4 -4
  369. package/dist/chunks/chunk-2MHDV5BF.js.map +0 -7
  370. package/dist/chunks/chunk-AZQYF6KE.js.map +0 -7
  371. package/dist/chunks/chunk-GZHGVVW3.js.map +0 -7
  372. package/dist/chunks/chunk-H3GJ4H2U.js.map +0 -7
  373. package/dist/chunks/chunk-I7YIGZXT.js.map +0 -7
  374. package/dist/chunks/chunk-IGYR22T6.js.map +0 -7
  375. package/dist/chunks/chunk-JGP5A3Y5.js.map +0 -7
  376. package/dist/chunks/chunk-JGWFTO6P.js.map +0 -7
  377. package/dist/chunks/chunk-O3NAGJP4.js.map +0 -7
  378. package/dist/chunks/chunk-QB2LNO4W.js.map +0 -7
  379. package/dist/chunks/chunk-R6XHAFBF.js.map +0 -7
  380. package/dist/chunks/chunk-UB44F4Z2.js.map +0 -7
  381. package/dist/chunks/chunk-WQFG7PAH.js.map +0 -7
  382. package/dist/chunks/chunk-X754AHS5.js.map +0 -7
  383. package/dist/chunks/chunk-YBLHKYFF.js.map +0 -7
  384. package/dist/chunks/configService-R3OGU2UD.js +0 -13
  385. /package/dist/chunks/{configService-R3OGU2UD.js.map → configService-PRJZF7Y6.js.map} +0 -0
  386. /package/dist/chunks/{constants-STK2YBIW.js.map → constants-KIQEYMAM.js.map} +0 -0
  387. /package/dist/chunks/{fs-JGINUXGL.js.map → fs-ZI5JEU7V.js.map} +0 -0
@@ -3,25 +3,29 @@
3
3
  * Handles rendering of locale/language switcher nodes
4
4
  */
5
5
 
6
- import { createElement as h } from "react";
7
- import type { ReactElement } from "react";
8
- import type { LocaleListNode, StyleObject, ResponsiveStyleObject, InteractiveStyles } from "../../../shared/types";
9
- import { extractAttributesFromNode } from "../../../shared/attributeNodeUtils";
10
- import { responsiveStylesToClasses } from "../../../shared/utilityClassMapper";
11
- import { getCachedResponsiveScalesConfig } from "../../responsiveStyleResolver";
12
- import { pathToString } from "../../../shared/pathArrayUtils";
13
- import { generateElementClassName, type ElementClassContext } from "../../../shared/elementClassName";
14
- import { InteractiveStylesRegistry } from "../../InteractiveStylesRegistry";
15
- import { hasInteractiveStyleMappings, extractInteractiveStyleMappings, resolveExtractedMappings } from "../../../shared/interactiveStyleMappings";
16
- import { UtilityClassCollector } from "../../styles/UtilityClassCollector";
17
- import type { ElementRegistry } from "../../elementRegistry";
18
- import type { BuilderContext } from "./types";
6
+ import { createElement as h } from 'react';
7
+ import type { ReactElement } from 'react';
8
+ import type { LocaleListNode, StyleObject, ResponsiveStyleObject, InteractiveStyles } from '../../../shared/types';
9
+ import { extractAttributesFromNode } from '../../../shared/attributeNodeUtils';
10
+ import { responsiveStylesToClasses } from '../../../shared/utilityClassMapper';
11
+ import { getCachedResponsiveScalesConfig } from '../../responsiveStyleResolver';
12
+ import { pathToString } from '../../../shared/pathArrayUtils';
13
+ import { generateElementClassName, type ElementClassContext } from '../../../shared/elementClassName';
14
+ import { InteractiveStylesRegistry } from '../../InteractiveStylesRegistry';
15
+ import {
16
+ hasInteractiveStyleMappings,
17
+ extractInteractiveStyleMappings,
18
+ resolveExtractedMappings,
19
+ } from '../../../shared/interactiveStyleMappings';
20
+ import { UtilityClassCollector } from '../../styles/UtilityClassCollector';
21
+ import type { ElementRegistry } from '../../elementRegistry';
22
+ import type { BuilderContext } from './types';
19
23
 
20
24
  export interface LocaleListBuilderDeps {
21
25
  elementRegistry: ElementRegistry;
22
26
  getEffectiveParentComponentName: (
23
27
  componentContext: string | null,
24
- parentComponentName: string | null
28
+ parentComponentName: string | null,
25
29
  ) => string | null;
26
30
  /** Optional getter for current page name (for interactive styles class generation) */
27
31
  getCurrentPageName?: () => string;
@@ -32,14 +36,16 @@ export interface LocaleListBuilderDeps {
32
36
  /**
33
37
  * Build a locale list node (language switcher)
34
38
  */
35
- export function buildLocaleList(
36
- node: LocaleListNode,
37
- ctx: BuilderContext,
38
- deps: LocaleListBuilderDeps
39
- ): ReactElement {
39
+ export function buildLocaleList(node: LocaleListNode, ctx: BuilderContext, deps: LocaleListBuilderDeps): ReactElement {
40
40
  const {
41
- key, elementPath, parentComponentName, componentContext, componentRootPath,
42
- locale, i18nConfig, cmsItemIndexPath
41
+ key,
42
+ elementPath,
43
+ parentComponentName,
44
+ componentContext,
45
+ componentRootPath,
46
+ locale,
47
+ i18nConfig,
48
+ cmsItemIndexPath,
43
49
  } = ctx;
44
50
 
45
51
  const effectiveParentComponentName = deps.getEffectiveParentComponentName(componentContext, parentComponentName);
@@ -63,7 +69,7 @@ export function buildLocaleList(
63
69
  }
64
70
  }
65
71
  }
66
- }
72
+ },
67
73
  };
68
74
 
69
75
  // Add CMS item index path for elements inside CMS lists
@@ -72,7 +78,7 @@ export function buildLocaleList(
72
78
  }
73
79
 
74
80
  // Start building className
75
- let classNames: string[] = [];
81
+ const classNames: string[] = [];
76
82
 
77
83
  // Resolve fluid mode once for all conversions in this builder
78
84
  const scales = getCachedResponsiveScalesConfig();
@@ -80,10 +86,10 @@ export function buildLocaleList(
80
86
 
81
87
  // Convert container styles to utility classes
82
88
  if (node.style) {
83
- const utilityClasses = responsiveStylesToClasses(
84
- node.style as StyleObject | ResponsiveStyleObject,
85
- { fluidActive, responsiveScales: scales ?? undefined }
86
- );
89
+ const utilityClasses = responsiveStylesToClasses(node.style as StyleObject | ResponsiveStyleObject, {
90
+ fluidActive,
91
+ responsiveScales: scales ?? undefined,
92
+ });
87
93
  UtilityClassCollector.collect(utilityClasses);
88
94
  classNames.push(...utilityClasses);
89
95
  }
@@ -96,11 +102,10 @@ export function buildLocaleList(
96
102
  if ((nodeInteractiveStyles && nodeInteractiveStyles.length > 0) || nodeGenerateElementClass) {
97
103
  // Determine file type and name for element class generation
98
104
  const useComponentContext = Boolean(componentContext);
99
- const fileType = useComponentContext ? 'component' : (deps.getCurrentFileType?.() || 'page');
100
- const fileName = useComponentContext ? componentContext! : (deps.getCurrentPageName?.() || 'page');
101
- const pathForClass = useComponentContext && componentRootPath
102
- ? elementPath.slice(componentRootPath.length)
103
- : elementPath;
105
+ const fileType = useComponentContext ? 'component' : deps.getCurrentFileType?.() || 'page';
106
+ const fileName = useComponentContext ? componentContext! : deps.getCurrentPageName?.() || 'page';
107
+ const pathForClass =
108
+ useComponentContext && componentRootPath ? elementPath.slice(componentRootPath.length) : elementPath;
104
109
 
105
110
  const elementClassCtx: ElementClassContext = {
106
111
  fileType,
@@ -131,10 +136,10 @@ export function buildLocaleList(
131
136
  const previewClasses: string[] = [];
132
137
  for (const rule of nodeInteractiveStyles) {
133
138
  if (rule.previewProp && ctx.componentResolvedProps[rule.previewProp] === true) {
134
- const styleClasses = responsiveStylesToClasses(
135
- rule.style as StyleObject | ResponsiveStyleObject,
136
- { fluidActive, responsiveScales: scales ?? undefined }
137
- );
139
+ const styleClasses = responsiveStylesToClasses(rule.style as StyleObject | ResponsiveStyleObject, {
140
+ fluidActive,
141
+ responsiveScales: scales ?? undefined,
142
+ });
138
143
  UtilityClassCollector.collect(styleClasses);
139
144
  previewClasses.push(...styleClasses);
140
145
  }
@@ -151,9 +156,9 @@ export function buildLocaleList(
151
156
  // would be spread onto the React element below and override the className that
152
157
  // holds the utility classes derived from node.style.
153
158
  if ('class' in extractedAttributes || 'className' in extractedAttributes) {
154
- const attrClass = ((extractedAttributes as Record<string, unknown>).class
155
- ?? (extractedAttributes as Record<string, unknown>).className
156
- ?? '') as string;
159
+ const attrClass = ((extractedAttributes as Record<string, unknown>).class ??
160
+ (extractedAttributes as Record<string, unknown>).className ??
161
+ '') as string;
157
162
  if (attrClass) {
158
163
  classNames.push(...attrClass.split(/\s+/));
159
164
  }
@@ -188,10 +193,30 @@ export function buildLocaleList(
188
193
  const currentLocaleCode = locale || i18nConfig?.defaultLocale || 'en';
189
194
 
190
195
  // Convert item styles, active item styles, separator styles, and flag styles to utility classes
191
- const itemClasses = node.itemStyle ? responsiveStylesToClasses(node.itemStyle as StyleObject | ResponsiveStyleObject, { fluidActive, responsiveScales: scales ?? undefined }) : [];
192
- const activeItemClasses = node.activeItemStyle ? responsiveStylesToClasses(node.activeItemStyle as StyleObject | ResponsiveStyleObject, { fluidActive, responsiveScales: scales ?? undefined }) : [];
193
- const separatorClasses = node.separatorStyle ? responsiveStylesToClasses(node.separatorStyle as StyleObject | ResponsiveStyleObject, { fluidActive, responsiveScales: scales ?? undefined }) : [];
194
- const flagClasses = node.flagStyle ? responsiveStylesToClasses(node.flagStyle as StyleObject | ResponsiveStyleObject, { fluidActive, responsiveScales: scales ?? undefined }) : [];
196
+ const itemClasses = node.itemStyle
197
+ ? responsiveStylesToClasses(node.itemStyle as StyleObject | ResponsiveStyleObject, {
198
+ fluidActive,
199
+ responsiveScales: scales ?? undefined,
200
+ })
201
+ : [];
202
+ const activeItemClasses = node.activeItemStyle
203
+ ? responsiveStylesToClasses(node.activeItemStyle as StyleObject | ResponsiveStyleObject, {
204
+ fluidActive,
205
+ responsiveScales: scales ?? undefined,
206
+ })
207
+ : [];
208
+ const separatorClasses = node.separatorStyle
209
+ ? responsiveStylesToClasses(node.separatorStyle as StyleObject | ResponsiveStyleObject, {
210
+ fluidActive,
211
+ responsiveScales: scales ?? undefined,
212
+ })
213
+ : [];
214
+ const flagClasses = node.flagStyle
215
+ ? responsiveStylesToClasses(node.flagStyle as StyleObject | ResponsiveStyleObject, {
216
+ fluidActive,
217
+ responsiveScales: scales ?? undefined,
218
+ })
219
+ : [];
195
220
  UtilityClassCollector.collect(itemClasses);
196
221
  UtilityClassCollector.collect(activeItemClasses);
197
222
  UtilityClassCollector.collect(separatorClasses);
@@ -206,21 +231,25 @@ export function buildLocaleList(
206
231
 
207
232
  // Add separator between links (empty span styled via separatorStyle)
208
233
  if (showSeparator && linkElements.length > 0) {
209
- linkElements.push(h('span', {
210
- key: `sep-${i}`,
211
- className: separatorClasses.length > 0 ? separatorClasses.join(' ') : undefined
212
- }));
234
+ linkElements.push(
235
+ h('span', {
236
+ key: `sep-${i}`,
237
+ className: separatorClasses.length > 0 ? separatorClasses.join(' ') : undefined,
238
+ }),
239
+ );
213
240
  }
214
241
 
215
242
  // Build link element content - flag icon (if enabled and exists) + nativeName in span
216
243
  const linkContent: (ReactElement | string)[] = [];
217
244
  if (showFlag && localeConfig.icon) {
218
- linkContent.push(h('img', {
219
- key: 'flag',
220
- src: localeConfig.icon,
221
- alt: `${localeConfig.name} flag`,
222
- className: flagClasses.length > 0 ? flagClasses.join(' ') : undefined
223
- }));
245
+ linkContent.push(
246
+ h('img', {
247
+ key: 'flag',
248
+ src: localeConfig.icon,
249
+ alt: `${localeConfig.name} flag`,
250
+ className: flagClasses.length > 0 ? flagClasses.join(' ') : undefined,
251
+ }),
252
+ );
224
253
  }
225
254
  // Get display text based on displayType (mirrors SSR logic)
226
255
  const displayType = node.displayType || 'nativeName';
@@ -241,13 +270,19 @@ export function buildLocaleList(
241
270
 
242
271
  // Current item gets both itemClasses + activeItemClasses (additive/override)
243
272
  const linkClasses = isCurrent ? [...itemClasses, ...activeItemClasses] : itemClasses;
244
- linkElements.push(h('div', {
245
- key: `locale-${localeConfig.code}`,
246
- 'data-current': isCurrent ? 'true' : 'false',
247
- 'data-locale': localeConfig.code,
248
- className: linkClasses.length > 0 ? linkClasses.join(' ') : undefined,
249
- style: { cursor: 'pointer' }
250
- }, ...linkContent));
273
+ linkElements.push(
274
+ h(
275
+ 'div',
276
+ {
277
+ key: `locale-${localeConfig.code}`,
278
+ 'data-current': isCurrent ? 'true' : 'false',
279
+ 'data-locale': localeConfig.code,
280
+ className: linkClasses.length > 0 ? linkClasses.join(' ') : undefined,
281
+ style: { cursor: 'pointer' },
282
+ },
283
+ ...linkContent,
284
+ ),
285
+ );
251
286
  }
252
287
 
253
288
  return h('div', localeListProps, linkElements);
@@ -2,11 +2,11 @@
2
2
  * Shared types for ComponentBuilder modules
3
3
  */
4
4
 
5
- import type { ReactElement } from "react";
6
- import type { ComponentNode } from "../../../shared/types";
7
- import type { Path } from "../../../shared/pathArrayUtils";
8
- import type { I18nConfig } from "../../../shared/types/components";
9
- import type { CMSItem, ItemContext, TemplateContext } from "../../../shared/types/cms";
5
+ import type { ReactElement } from 'react';
6
+ import type { ComponentNode } from '../../../shared/types';
7
+ import type { Path } from '../../../shared/pathArrayUtils';
8
+ import type { I18nConfig } from '../../../shared/types/components';
9
+ import type { CMSItem, ItemContext, TemplateContext } from '../../../shared/types/cms';
10
10
 
11
11
  export type ComponentProps = Record<string, unknown>;
12
12
 
@@ -60,11 +60,7 @@ function resolveI18nValue(value: I18nValue, locale: string, config: I18nConfig):
60
60
  * @param locale - Optional locale for i18n resolution (defaults to config's defaultLocale)
61
61
  * @returns Processed string with values filled in
62
62
  */
63
- export function processCMSTemplate(
64
- template: string,
65
- cmsItem: Record<string, unknown>,
66
- locale?: string
67
- ): string {
63
+ export function processCMSTemplate(template: string, cmsItem: Record<string, unknown>, locale?: string): string {
68
64
  const config = getI18nConfig();
69
65
  const effectiveLocale = locale || config.defaultLocale;
70
66
 
@@ -94,7 +90,11 @@ export function processCMSTemplate(
94
90
  }
95
91
  // Handle rich-text markers - extract HTML content for interpolation
96
92
  // Mark with RAW_HTML_PREFIX so renderer knows not to escape
97
- if (typeof value === 'object' && '__richtext__' in value && typeof (value as unknown as { html: string }).html === 'string') {
93
+ if (
94
+ typeof value === 'object' &&
95
+ '__richtext__' in value &&
96
+ typeof (value as unknown as { html: string }).html === 'string'
97
+ ) {
98
98
  return RAW_HTML_PREFIX + (value as unknown as { html: string }).html;
99
99
  }
100
100
  // Handle raw TipTap documents (fallback if not preprocessed)
@@ -118,7 +118,7 @@ export function processCMSTemplate(
118
118
  export function processCMSPropsTemplate(
119
119
  props: Record<string, unknown>,
120
120
  cmsItem: Record<string, unknown>,
121
- locale?: string
121
+ locale?: string,
122
122
  ): Record<string, unknown> {
123
123
  const result: Record<string, unknown> = {};
124
124
 
@@ -27,7 +27,7 @@ export class ElementRegistry {
27
27
  _componentName?: string | null,
28
28
  _isComponentRoot?: boolean,
29
29
  _props?: Record<string, unknown>,
30
- _metadata?: Partial<ElementMetadata>
30
+ _metadata?: Partial<ElementMetadata>,
31
31
  ): void {
32
32
  // No-op in core - element tracking is editor-only
33
33
  }
@@ -81,7 +81,7 @@ export class ElementRegistry {
81
81
  _path: Path | string,
82
82
  _itemIndex: number,
83
83
  _element: HTMLElement | null,
84
- _metadata?: Partial<ElementMetadata>
84
+ _metadata?: Partial<ElementMetadata>,
85
85
  ): void {
86
86
  // No-op in core - element tracking is editor-only
87
87
  }
@@ -105,7 +105,7 @@ let _elementRegistry: ElementRegistry = new ElementRegistry();
105
105
  export const elementRegistry: ElementRegistry = new Proxy({} as ElementRegistry, {
106
106
  get(_target, prop) {
107
107
  return (_elementRegistry as any)[prop];
108
- }
108
+ },
109
109
  });
110
110
 
111
111
  /**
@@ -1,9 +1,5 @@
1
1
  import { describe, test, expect, beforeEach, afterEach, mock } from 'bun:test';
2
- import {
3
- fetchFontFamilies,
4
- getCachedFontFamilies,
5
- invalidateFontFamilies,
6
- } from './fontFamiliesService';
2
+ import { fetchFontFamilies, getCachedFontFamilies, invalidateFontFamilies } from './fontFamiliesService';
7
3
 
8
4
  const realFetch = globalThis.fetch;
9
5
 
@@ -36,11 +32,7 @@ describe('fontFamiliesService', () => {
36
32
 
37
33
  test('fetchFontFamilies dedupes families that repeat across weights/unicode-ranges', async () => {
38
34
  mockFetchOnce({
39
- fonts: [
40
- { family: 'Fraunces', weight: 400 },
41
- { family: 'Fraunces', weight: 700 },
42
- { family: 'Inter' },
43
- ],
35
+ fonts: [{ family: 'Fraunces', weight: 400 }, { family: 'Fraunces', weight: 700 }, { family: 'Inter' }],
44
36
  });
45
37
  const families = await fetchFontFamilies();
46
38
  expect(families).toEqual(['Fraunces', 'Inter']);
@@ -15,7 +15,7 @@ function extractFamilyFromPath(path: string): string {
15
15
  const name = filename.replace(/\.(ttf|woff2?|otf)$/i, '');
16
16
  return name
17
17
  .split('-')
18
- .map(part => part.charAt(0).toUpperCase() + part.slice(1))
18
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
19
19
  .join(' ');
20
20
  }
21
21
 
@@ -38,8 +38,8 @@ export async function fetchFontFamilies(): Promise<string[]> {
38
38
  if (inFlight) return inFlight;
39
39
 
40
40
  inFlight = fetch('/api/config')
41
- .then(res => (res.ok ? res.json() : { fonts: [] }))
42
- .then(config => {
41
+ .then((res) => (res.ok ? res.json() : { fonts: [] }))
42
+ .then((config) => {
43
43
  cachedFamilies = extractFamilies(config.fonts);
44
44
  return cachedFamilies;
45
45
  })
@@ -95,6 +95,14 @@ export function HMRManager({
95
95
  } else if (data.type === 'hmr:libraries-update') {
96
96
  // Dispatch custom event to trigger full page reload for library changes
97
97
  document.dispatchEvent(new CustomEvent('hmr-libraries-update'));
98
+ } else if (data.type === 'hmr:config-update') {
99
+ // project.config.json changed (e.g. a locale was added in the editor).
100
+ // Dispatch custom event so the Router refetches the i18n config and
101
+ // re-resolves the current route — without this, the canvas keeps the
102
+ // stale locale set and a freshly added locale's paths (/pl) 404 with
103
+ // "Page not found" until a full canvas reload. The studio frame has its
104
+ // own handler for the same WS message (editor.tsx); this is the canvas's.
105
+ document.dispatchEvent(new CustomEvent('hmr-config-update'));
98
106
  }
99
107
  };
100
108
 
@@ -32,7 +32,7 @@ async function injectUpdatedThemeCSS(): Promise<void> {
32
32
  const themesResponse = await fetch('/api/themes');
33
33
  if (!themesResponse.ok) return;
34
34
 
35
- const themesData = await themesResponse.json() as {
35
+ const themesData = (await themesResponse.json()) as {
36
36
  themes: Array<{ name: string; label: string }>;
37
37
  default: string;
38
38
  };
@@ -40,9 +40,7 @@ async function injectUpdatedThemeCSS(): Promise<void> {
40
40
  // Fetch colors for each theme
41
41
  const themeColors: Record<string, any> = {};
42
42
  for (const theme of themesData.themes) {
43
- const colorResponse = await fetch(
44
- `/api/colors?theme=${encodeURIComponent(theme.name)}`
45
- );
43
+ const colorResponse = await fetch(`/api/colors?theme=${encodeURIComponent(theme.name)}`);
46
44
  if (colorResponse.ok) {
47
45
  themeColors[theme.name] = (await colorResponse.json()).colors;
48
46
  }
@@ -140,21 +138,29 @@ export function setupCssHmrListeners(): void {
140
138
 
141
139
  if (!window.__hmrColorsInitialized) {
142
140
  window.__hmrColorsInitialized = true;
143
- document.addEventListener('hmr-colors-update', () => { void injectUpdatedThemeCSS(); });
141
+ document.addEventListener('hmr-colors-update', () => {
142
+ void injectUpdatedThemeCSS();
143
+ });
144
144
  }
145
145
 
146
146
  if (!window.__hmrVariablesCSSInitialized) {
147
147
  window.__hmrVariablesCSSInitialized = true;
148
- document.addEventListener('hmr-variables-update', () => { void injectUpdatedVariablesCSS(); });
148
+ document.addEventListener('hmr-variables-update', () => {
149
+ void injectUpdatedVariablesCSS();
150
+ });
149
151
  }
150
152
 
151
153
  if (!window.__hmrFontsCSSInitialized) {
152
154
  window.__hmrFontsCSSInitialized = true;
153
- document.addEventListener('hmr-fonts-update', () => { void injectUpdatedFontsCSS(); });
155
+ document.addEventListener('hmr-fonts-update', () => {
156
+ void injectUpdatedFontsCSS();
157
+ });
154
158
  }
155
159
 
156
160
  if (!window.__hmrLibrariesInitialized) {
157
161
  window.__hmrLibrariesInitialized = true;
158
- document.addEventListener('hmr-libraries-update', () => { location.reload(); });
162
+ document.addEventListener('hmr-libraries-update', () => {
163
+ location.reload();
164
+ });
159
165
  }
160
166
  }
@@ -56,16 +56,14 @@ export class HMRWebSocket {
56
56
 
57
57
  this.isIntentionallyClosed = false;
58
58
  this.config.onStatusChange('connecting');
59
-
60
59
 
61
60
  try {
62
61
  this.ws = new WebSocket(this.config.url);
63
-
62
+
64
63
  this.ws.onopen = () => this.handleOpen();
65
64
  this.ws.onmessage = (event) => this.handleMessage(event);
66
65
  this.ws.onerror = (error) => this.handleError(error);
67
66
  this.ws.onclose = (event) => this.handleClose(event);
68
-
69
67
  } catch (error) {
70
68
  this.scheduleReconnect();
71
69
  }
@@ -74,10 +72,10 @@ export class HMRWebSocket {
74
72
  private handleOpen(): void {
75
73
  this.reconnectAttempts = 0;
76
74
  this.config.onStatusChange('connected');
77
-
75
+
78
76
  // Start heartbeat
79
77
  this.startHeartbeat();
80
-
78
+
81
79
  // Flush queued messages
82
80
  this.flushMessageQueue();
83
81
  }
@@ -102,9 +100,8 @@ export class HMRWebSocket {
102
100
  }
103
101
 
104
102
  private handleClose(event: CloseEvent): void {
105
-
106
103
  this.stopHeartbeat();
107
-
104
+
108
105
  if (!this.isIntentionallyClosed) {
109
106
  this.config.onStatusChange('disconnected');
110
107
  this.scheduleReconnect();
@@ -134,15 +131,14 @@ export class HMRWebSocket {
134
131
 
135
132
  // Exponential backoff with jitter
136
133
  const delay = Math.min(
137
- this.config.initialReconnectDelay * Math.pow(2, this.reconnectAttempts),
138
- this.config.maxReconnectDelay
134
+ this.config.initialReconnectDelay * 2 ** this.reconnectAttempts,
135
+ this.config.maxReconnectDelay,
139
136
  );
140
-
137
+
141
138
  // Add jitter (±25%)
142
139
  const jitter = delay * 0.25 * (Math.random() - 0.5);
143
140
  const finalDelay = Math.max(delay + jitter, 100);
144
141
 
145
-
146
142
  this.reconnectTimeout = setTimeout(() => {
147
143
  this.reconnectAttempts++;
148
144
  this.connect();
@@ -205,7 +201,7 @@ export class HMRWebSocket {
205
201
  */
206
202
  getStatus(): 'connecting' | 'connected' | 'disconnected' | 'closed' {
207
203
  if (!this.ws) return 'disconnected';
208
-
204
+
209
205
  switch (this.ws.readyState) {
210
206
  case WebSocket.CONNECTING:
211
207
  return 'connecting';
@@ -225,7 +221,7 @@ export class HMRWebSocket {
225
221
  close(): void {
226
222
  this.isIntentionallyClosed = true;
227
223
  this.stopHeartbeat();
228
-
224
+
229
225
  if (this.reconnectTimeout) {
230
226
  clearTimeout(this.reconnectTimeout);
231
227
  this.reconnectTimeout = null;
@@ -266,4 +262,3 @@ export class HMRWebSocket {
266
262
  this.config.onStatusChange = handler;
267
263
  }
268
264
  }
269
-
@@ -12,10 +12,10 @@ describe('useColorVariables utilities', () => {
12
12
  test('returns all color variables when input is empty', () => {
13
13
  const colors: ColorVariables = {
14
14
  colors: {
15
- 'primary': '#007acc',
16
- 'secondary': '#6b7280',
17
- 'background': '#ffffff'
18
- }
15
+ primary: '#007acc',
16
+ secondary: '#6b7280',
17
+ background: '#ffffff',
18
+ },
19
19
  };
20
20
 
21
21
  const result = getColorVariableSuggestions(colors, '');
@@ -28,11 +28,11 @@ describe('useColorVariables utilities', () => {
28
28
  test('filters color variables by input', () => {
29
29
  const colors: ColorVariables = {
30
30
  colors: {
31
- 'primary': '#007acc',
31
+ primary: '#007acc',
32
32
  'primary-light': '#0098ff',
33
- 'secondary': '#6b7280',
34
- 'background': '#ffffff'
35
- }
33
+ secondary: '#6b7280',
34
+ background: '#ffffff',
35
+ },
36
36
  };
37
37
 
38
38
  const result = getColorVariableSuggestions(colors, 'primary');
@@ -44,9 +44,9 @@ describe('useColorVariables utilities', () => {
44
44
  test('is case insensitive', () => {
45
45
  const colors: ColorVariables = {
46
46
  colors: {
47
- 'Primary': '#007acc',
48
- 'SECONDARY': '#6b7280'
49
- }
47
+ Primary: '#007acc',
48
+ SECONDARY: '#6b7280',
49
+ },
50
50
  };
51
51
 
52
52
  const result = getColorVariableSuggestions(colors, 'primary');
@@ -57,9 +57,9 @@ describe('useColorVariables utilities', () => {
57
57
  test('handles whitespace in input', () => {
58
58
  const colors: ColorVariables = {
59
59
  colors: {
60
- 'primary': '#007acc',
61
- 'secondary': '#6b7280'
62
- }
60
+ primary: '#007acc',
61
+ secondary: '#6b7280',
62
+ },
63
63
  };
64
64
 
65
65
  const result = getColorVariableSuggestions(colors, ' primary ');
@@ -72,8 +72,8 @@ describe('useColorVariables utilities', () => {
72
72
  colors: {
73
73
  'text-primary': '#000000',
74
74
  'text-secondary': '#6b7280',
75
- 'background': '#ffffff'
76
- }
75
+ background: '#ffffff',
76
+ },
77
77
  };
78
78
 
79
79
  const result = getColorVariableSuggestions(colors, 'text');
@@ -85,8 +85,8 @@ describe('useColorVariables utilities', () => {
85
85
  test('formats variables correctly', () => {
86
86
  const colors: ColorVariables = {
87
87
  colors: {
88
- 'my-color': '#ff0000'
89
- }
88
+ 'my-color': '#ff0000',
89
+ },
90
90
  };
91
91
 
92
92
  const result = getColorVariableSuggestions(colors, 'my');
@@ -96,9 +96,9 @@ describe('useColorVariables utilities', () => {
96
96
  test('returns empty array when no matches', () => {
97
97
  const colors: ColorVariables = {
98
98
  colors: {
99
- 'primary': '#007acc',
100
- 'secondary': '#6b7280'
101
- }
99
+ primary: '#007acc',
100
+ secondary: '#6b7280',
101
+ },
102
102
  };
103
103
 
104
104
  const result = getColorVariableSuggestions(colors, 'nonexistent');