@designcrowd/library.brand-page 6.2.11 → 6.2.12

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 (576) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-DDcraD5S.js → CreatedOnBrandCrowd-de-de-BtVKllNQ.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-DtOeaisf.js → CreatedOnBrandCrowd-en-us-CX5V0v8u.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-BZpmJPew.js → CreatedOnBrandCrowd-es-es-CbA02PCL.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-CqRwC4e7.js → CreatedOnBrandCrowd-fr-ca-BQAKruBF.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-CqRwC4e7.js → CreatedOnBrandCrowd-fr-fr-BQAKruBF.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-DId9Dfjh.js → CreatedOnBrandCrowd-pt-br-Yk_yzB3s.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-DId9Dfjh.js → CreatedOnBrandCrowd-pt-pt-Yk_yzB3s.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-BTDfmOcm.js → CreatedOnDcom-de-de-DJZQbPSD.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-CeAu9Ayx.js → CreatedOnDcom-en-us-BJvNAa4l.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-WCv0K41H.js → CreatedOnDcom-es-es-CUwB1FRY.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-BlfevQDY.js → CreatedOnDcom-fr-ca-CK54U4oh.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-Cvt7MHPZ.js → CreatedOnDcom-fr-fr-DuUNBGrM.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-DipZuylv.js → CreatedOnDcom-pt-br-BfODpFNV.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-BCw4lcKN.js → CreatedOnDcom-pt-pt-Cf6u2GCg.js} +1 -1
  15. package/lib/src/brand-page/__fixtures__/production-text-style-resolver.fixture.d.ts +16 -0
  16. package/lib/src/brand-page/__fixtures__/production-text-style-resolver.fixture.js +35 -0
  17. package/lib/src/brand-page/components/contact-form/ContactForm.mixin.d.ts +3 -0
  18. package/lib/src/brand-page/components/contact-form/ContactForm.mixin.js +19 -13
  19. package/lib/src/brand-page/components/mailing-list/MailingList.mixin.d.ts +3 -1
  20. package/lib/src/brand-page/components/mailing-list/MailingList.mixin.js +17 -2
  21. package/lib/src/brand-page/components/navigation/button-carousel/ButtonCarouselNavigation.mixin.d.ts +11 -3
  22. package/lib/src/brand-page/components/navigation/button-carousel/ButtonCarouselNavigation.mixin.js +35 -1
  23. package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.d.ts +8 -2
  24. package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.js +27 -3
  25. package/lib/src/brand-page/components/page/Page.mixin.d.ts +5 -2
  26. package/lib/src/brand-page/components/page/Page.mixin.js +33 -27
  27. package/lib/src/brand-page/components/page-footer/PageFooter.mixin.d.ts +7 -2
  28. package/lib/src/brand-page/components/page-footer/PageFooter.mixin.js +21 -1
  29. package/lib/src/brand-page/components/payment/Payment.mixin.d.ts +5 -2
  30. package/lib/src/brand-page/components/payment/Payment.mixin.js +22 -2
  31. package/lib/src/brand-page/components/payment/support-me/SupportMe.mixin.d.ts +6 -2
  32. package/lib/src/brand-page/components/payment/support-me/SupportMe.mixin.js +32 -1
  33. package/lib/src/brand-page/components/social-links/SocialLinks.stories.js +0 -3
  34. package/lib/src/brand-page/components/testimonial-section/__fixtures__/data.js +0 -3
  35. package/lib/src/brand-page/components/text/Text.stories.js +0 -17
  36. package/lib/src/brand-page/constants/font.constants.d.ts +62 -0
  37. package/lib/src/brand-page/constants/font.constants.js +35 -0
  38. package/lib/src/brand-page/models/index.d.ts +23 -24
  39. package/lib/src/brand-page/models/index.js +20 -7
  40. package/lib/src/brand-page/models/navigation-styles.model.d.ts +1 -1
  41. package/lib/src/brand-page/models/navigation-styles.model.js +17 -8
  42. package/lib/src/brand-page/models/payment.model.d.ts +11 -6
  43. package/lib/src/brand-page/models/styles.model.d.ts +53 -7
  44. package/lib/src/brand-page/models/styles.model.js +115 -27
  45. package/lib/src/brand-page/utils/color-palette.util.d.ts +43 -23
  46. package/lib/src/brand-page/utils/color-palette.util.js +65 -27
  47. package/lib/src/brand-page/utils/color.util.d.ts +13 -9
  48. package/lib/src/brand-page/utils/color.util.js +56 -15
  49. package/lib/src/brand-page/utils/container-text-color.util.d.ts +46 -13
  50. package/lib/src/brand-page/utils/container-text-color.util.js +321 -41
  51. package/lib/src/brand-page/utils/index.d.ts +1 -0
  52. package/lib/src/brand-page/utils/index.js +1 -0
  53. package/lib/src/brand-page/utils/migration/migration-20.js +6 -2
  54. package/lib/src/brand-page/utils/migration/migration-21.js +34 -6
  55. package/lib/src/brand-page/utils/migration/migration-22.d.ts +99 -0
  56. package/lib/src/brand-page/utils/migration/migration-22.js +909 -0
  57. package/lib/src/brand-page/utils/migration.util.js +17 -0
  58. package/lib/src/brand-page/utils/model.util.d.ts +4 -0
  59. package/lib/src/brand-page/utils/model.util.js +4 -0
  60. package/lib/src/brand-page/utils/personalisation.util.js +9 -1
  61. package/lib/src/brand-page/utils/rte-role-lift.util.d.ts +72 -0
  62. package/lib/src/brand-page/utils/rte-role-lift.util.js +275 -0
  63. package/lib/src/brand-page/utils/style.util.d.ts +5 -1
  64. package/lib/src/brand-page/utils/style.util.js +34 -11
  65. package/lib/src/brand-page/utils/text-role-css.util.d.ts +19 -0
  66. package/lib/src/brand-page/utils/text-role-css.util.js +186 -0
  67. package/lib/src/brand-page/utils/text-role-reconnect.util.d.ts +90 -0
  68. package/lib/src/brand-page/utils/text-role-reconnect.util.js +434 -0
  69. package/lib/src/brand-page/utils/text-style.util.d.ts +53 -23
  70. package/lib/src/brand-page/utils/text-style.util.js +122 -22
  71. package/lib/src/brand-page/utils/view-model.util.d.ts +9 -1
  72. package/lib/src/brand-page/utils/view-model.util.js +124 -111
  73. package/lib/src/brand-page/view-models.d.ts +1 -0
  74. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +4 -1
  75. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +13 -2
  76. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +4 -4
  77. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +4 -1
  78. package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.js +0 -10
  79. package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/content-settings-items.fixture.js +0 -1
  80. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +23 -138
  81. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.js +0 -28
  82. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +4 -1
  83. package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.d.ts +1 -1
  84. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +5 -2
  85. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +4 -1
  86. package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +4 -1
  87. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +4 -1
  88. package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.d.ts +1 -0
  89. package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.js +1 -0
  90. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +1 -0
  91. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/RoleTypographyFill.d.ts +16 -0
  92. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/RoleTypographyFill.js +61 -0
  93. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/RteClipboard.d.ts +11 -0
  94. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/RteClipboard.js +236 -0
  95. package/lib/src/brand-page-maker/composables/rich-text-editor/font.d.ts +2 -1
  96. package/lib/src/brand-page-maker/composables/rich-text-editor/font.js +25 -6
  97. package/lib/src/brand-page-maker/composables/rich-text-editor/formatting.d.ts +17 -4
  98. package/lib/src/brand-page-maker/composables/rich-text-editor/formatting.js +204 -17
  99. package/lib/src/brand-page-maker/composables/rich-text-editor/hyperlink.d.ts +1 -1
  100. package/lib/src/brand-page-maker/composables/rich-text-editor/hyperlink.js +29 -31
  101. package/lib/src/brand-page-maker/composables/rich-text-editor/keepMarksOnEmpty.d.ts +20 -0
  102. package/lib/src/brand-page-maker/composables/rich-text-editor/keepMarksOnEmpty.js +60 -0
  103. package/lib/src/brand-page-maker/composables/rich-text-editor/spacing.d.ts +2 -1
  104. package/lib/src/brand-page-maker/composables/rich-text-editor/spacing.js +22 -6
  105. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +10 -4
  106. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +319 -275
  107. package/lib/src/brand-page-maker/constants/config-settings-constant.js +1 -5
  108. package/lib/src/brand-page-maker/convertors/text-css-style-options.convertor.js +6 -2
  109. package/lib/src/brand-page-maker/convertors/text-size-value.convertor.d.ts +1 -1
  110. package/lib/src/brand-page-maker/convertors/text-size-value.convertor.js +3 -1
  111. package/lib/src/brand-page-maker/default-getters/payment-text-and-border-color.default-getter.js +7 -14
  112. package/lib/src/brand-page-maker/default-getters/text-color.default-getter.js +6 -13
  113. package/lib/src/brand-page-maker/models/content-settings.d.ts +8 -0
  114. package/lib/src/brand-page-maker/models/content-settings.js +112 -81
  115. package/lib/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store-utils.d.ts +2 -2
  116. package/lib/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store-utils.js +5 -2
  117. package/lib/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store.js +4 -3
  118. package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +1257 -117
  119. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +6 -1
  120. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +17 -9
  121. package/lib/src/brand-page-maker/stores/history/history-store.d.ts +59 -5
  122. package/lib/src/brand-page-maker/stores/history/history-store.js +22 -2
  123. package/lib/src/brand-page-maker/utils/apply-color-strategy.js +26 -8
  124. package/lib/src/brand-page-maker/utils/index.d.ts +2 -1
  125. package/lib/src/brand-page-maker/utils/index.js +2 -1
  126. package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +117 -15
  127. package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +435 -281
  128. package/lib/src/brand-page-maker/utils/rte-authoring.util.d.ts +4 -0
  129. package/lib/src/brand-page-maker/utils/rte-authoring.util.js +101 -0
  130. package/lib/src/brand-page-maker/utils/rte-clipboard.util.d.ts +126 -0
  131. package/lib/src/brand-page-maker/utils/rte-clipboard.util.js +307 -0
  132. package/lib/src/brand-page-maker/utils/rte-sanitize.util.js +13 -3
  133. package/lib/src/{bundled-translations-zfiA5Tsw.js → bundled-translations-yGrvPE5i.js} +17 -17
  134. package/lib/src/{bundled-translations.de-DE-ChsdSyAP.js → bundled-translations.de-DE-L4Znf8Hs.js} +17 -17
  135. package/lib/src/{bundled-translations.es-ES-DflsWQK0.js → bundled-translations.es-ES-D6iticrK.js} +15 -15
  136. package/lib/src/{bundled-translations.fr-CA-fpDRuZ52.js → bundled-translations.fr-CA-BgAVE-9k.js} +25 -25
  137. package/lib/src/{bundled-translations.fr-FR-Bub73Zt-.js → bundled-translations.fr-FR-B8GbyqxQ.js} +17 -17
  138. package/lib/src/{bundled-translations.pt-BR-BlnWE9TB.js → bundled-translations.pt-BR-DjPU3Db7.js} +25 -25
  139. package/lib/src/{bundled-translations.pt-PT-DmzXlnaS.js → bundled-translations.pt-PT-BaepaDpr.js} +23 -23
  140. package/lib/src/bundles/bundled-translations.de-DE.json +21 -2
  141. package/lib/src/bundles/bundled-translations.es-ES.json +21 -2
  142. package/lib/src/bundles/bundled-translations.fr-CA.json +21 -2
  143. package/lib/src/bundles/bundled-translations.fr-FR.json +21 -2
  144. package/lib/src/bundles/bundled-translations.json +21 -2
  145. package/lib/src/bundles/bundled-translations.pt-BR.json +21 -2
  146. package/lib/src/bundles/bundled-translations.pt-PT.json +21 -2
  147. package/lib/src/clients/ai-assistant-client.d.ts +1 -0
  148. package/lib/src/composables/useTranslate.d.ts +1 -1
  149. package/lib/src/composables/useTranslate.js +1 -1
  150. package/lib/src/css/library.brand-page-brandCrowd.min.css +303 -207
  151. package/lib/src/css/library.brand-page-brandPage.min.css +303 -207
  152. package/lib/src/css/library.brand-page-designCom.min.css +303 -207
  153. package/lib/src/css/library.brand-page-preview.min.css +303 -207
  154. package/lib/src/index.d.ts +2 -1
  155. package/lib/src/index.mjs +195 -191
  156. package/lib/src/{lib-1AqtEmvQ.js → lib-kGRlD3_P.js} +36855 -33893
  157. package/lib/src/lib.js +2 -1
  158. package/lib/src/metadata-builder/builders/footer-builder.js +4 -5
  159. package/lib/src/metadata-builder/builders/global-role-propagation.d.ts +58 -0
  160. package/lib/src/metadata-builder/builders/global-role-propagation.js +246 -0
  161. package/lib/src/metadata-builder/builders/global-styles-builder.d.ts +1 -0
  162. package/lib/src/metadata-builder/builders/global-styles-builder.js +116 -45
  163. package/lib/src/metadata-builder/builders/header-builder.js +13 -4
  164. package/lib/src/metadata-builder/builders/section-builders/about-section-builder.js +3 -3
  165. package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.js +3 -3
  166. package/lib/src/metadata-builder/builders/section-builders/booking-section-builder.js +3 -3
  167. package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.js +4 -4
  168. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +3 -3
  169. package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.js +2 -2
  170. package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.js +2 -2
  171. package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.js +4 -4
  172. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +3 -3
  173. package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +8 -2
  174. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +2 -2
  175. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +60 -29
  176. package/lib/src/metadata-builder/builders/section-field-maps.js +1 -0
  177. package/lib/src/metadata-builder/builders/section-field-utils.d.ts +48 -19
  178. package/lib/src/metadata-builder/builders/section-field-utils.js +128 -52
  179. package/lib/src/metadata-builder/builders/section-rules/global-styles.rules.d.ts +4 -2
  180. package/lib/src/metadata-builder/builders/section-rules/global-styles.rules.js +28 -12
  181. package/lib/src/metadata-builder/builders/section-rules/social-links.rules.js +5 -1
  182. package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +1 -1
  183. package/lib/src/metadata-builder/helpers/rte.helpers.js +97 -40
  184. package/lib/src/metadata-builder/metadata-executor.js +23 -1
  185. package/lib/src/metadata-builder/models.d.ts +2 -0
  186. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +18 -19
  187. package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +18 -1
  188. package/lib/src/metadata-builder/sanitizers/rte-schema-check.js +1 -1
  189. package/lib/src/metadata-builder/sanitizers/sanitizer-rules.d.ts +0 -1
  190. package/lib/src/metadata-builder/sanitizers/sanitizer-rules.js +5 -8
  191. package/lib/src/metadata-builder/sanitizers/section-args-validator.d.ts +7 -16
  192. package/lib/src/metadata-builder/sanitizers/section-args-validator.js +95 -22
  193. package/lib/src/shared/color-palette/section-color-matches.js +9 -25
  194. package/lib/src/shared/color-strategies/color-strategies.d.ts +15 -0
  195. package/lib/src/shared/color-strategies/color-strategies.js +31 -0
  196. package/lib/src/shared/color-strategies/rte-color.d.ts +8 -0
  197. package/lib/src/shared/color-strategies/rte-color.js +16 -0
  198. package/lib/src/shared/color-strategies/rte-field-pairs.d.ts +23 -0
  199. package/lib/src/shared/color-strategies/rte-field-pairs.js +28 -0
  200. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +9 -135
  201. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +1 -27
  202. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +12 -2
  203. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +7 -0
  204. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +75 -6
  205. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +18 -7
  206. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +6 -1
  207. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.js +0 -7
  208. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +1 -0
  209. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.js +8 -4
  210. package/lib/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.d.ts +1255 -26
  211. package/lib/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.js +203 -59
  212. package/lib/src/shared/content-settings/store/content-settings-store.d.ts +6 -0
  213. package/lib/src/shared/content-settings/store/content-settings-store.js +105 -8
  214. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +5 -1
  215. package/lib/src/shared/navigation-style-settings/store/index.d.ts +7 -3
  216. package/lib/src/shared/navigation-style-settings/store/index.js +40 -15
  217. package/lib/src/shared/page-settings/components/delete-page-modal/DeletePageModal.mixin.d.ts +1 -1
  218. package/lib/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.d.ts +1 -0
  219. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +17 -5
  220. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +70 -13
  221. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.js +10 -2
  222. package/lib/src/shared/page-settings/store/page-settings-store.d.ts +2 -1
  223. package/lib/src/shared/page-settings/store/page-settings-store.js +17 -0
  224. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +4 -1
  225. package/lib/src/shared/rte-extensions/AutoLink.d.ts +17 -0
  226. package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/AutoLink.js +67 -51
  227. package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/MaxLength.js +4 -1
  228. package/lib/src/shared/rte-extensions/TextEffects.d.ts +28 -0
  229. package/lib/src/shared/rte-extensions/TextEffects.js +96 -0
  230. package/lib/src/shared/rte-extensions/ViewDomParser.d.ts +2 -0
  231. package/lib/src/shared/rte-extensions/ViewDomParser.js +21 -0
  232. package/lib/src/shared/rte-extensions.util.d.ts +25 -0
  233. package/lib/src/{brand-page-maker/composables/rich-text-editor/getRteExtensions.js → shared/rte-extensions.util.js} +62 -7
  234. package/lib/src/shared/rte-link.util.d.ts +1 -0
  235. package/lib/src/shared/rte-link.util.js +1 -0
  236. package/lib/src/shared/rte-render.util.d.ts +112 -0
  237. package/lib/src/shared/rte-render.util.js +255 -0
  238. package/lib/src/shared/rte-shape.util.d.ts +6 -0
  239. package/lib/src/shared/rte-shape.util.js +18 -0
  240. package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +2 -1
  241. package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +1 -0
  242. package/lib/src/shared/side-bar/store/side-bar-store.d.ts +2 -0
  243. package/lib/src/shared/side-bar/store/side-bar-store.js +9 -0
  244. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +155 -15
  245. package/lib/src/shared/style-settings/components/StyleSettings.mixin.js +7 -1
  246. package/lib/src/shared/style-settings/store/style-settings-store.d.ts +1 -9
  247. package/lib/src/shared/style-settings/store/style-settings-store.js +3 -33
  248. package/lib/src/shared/style-settings/text-style-size-order.d.ts +2 -0
  249. package/lib/src/shared/style-settings/text-style-size-order.js +13 -0
  250. package/lib/src/shared/text-role-typography.util.d.ts +64 -0
  251. package/lib/src/shared/text-role-typography.util.js +183 -0
  252. package/lib/src/utils/minify-brand-page-metadata.d.ts +16 -1
  253. package/lib/src/utils/minify-brand-page-metadata.js +31 -9
  254. package/package.json +1 -1
  255. package/src/brand-page/__fixtures__/migration-22-v21/edited-brandsite-sections.v21.json +982 -0
  256. package/src/brand-page/__fixtures__/migration-22-v21/new-brandcontact-every-section.v21.json +1231 -0
  257. package/src/brand-page/__fixtures__/migration-22-v21/new-brandpage-every-section.v21.json +1231 -0
  258. package/src/brand-page/__fixtures__/migration-22-v21/new-brandsite-every-section.v21.json +1243 -0
  259. package/src/brand-page/__fixtures__/migration-22-v21/real-brandcontact.v21.json +755 -0
  260. package/src/brand-page/__fixtures__/migration-22-v21/real-brandpage-general-link.v21.json +527 -0
  261. package/src/brand-page/__fixtures__/migration-22-v21/real-brandpage-links.v21.json +755 -0
  262. package/src/brand-page/__fixtures__/migration-22-v21/real-brandpage-social-links.v21.json +514 -0
  263. package/src/brand-page/__fixtures__/migration-22-v21/real-brandsite-about.v21.json +459 -0
  264. package/src/brand-page/__fixtures__/migration-22-v21/real-brandsite-footer.v21.json +469 -0
  265. package/src/brand-page/__fixtures__/migration-22-v21/real-brandsite-header-banner.v21.json +481 -0
  266. package/src/brand-page/__fixtures__/migration-22-v21/real-brandsite-sections.v21.json +800 -0
  267. package/src/brand-page/__fixtures__/production-text-style-resolver.fixture.ts +52 -0
  268. package/src/brand-page/components/about-section/AboutSection.vue.test.ts +0 -10
  269. package/src/brand-page/components/contact-form/ContactForm.mixin.test.ts +127 -0
  270. package/src/brand-page/components/contact-form/ContactForm.mixin.ts +31 -14
  271. package/src/brand-page/components/contact-form/ContactForm.vue +26 -12
  272. package/src/brand-page/components/contact-form/ContactForm.vue.test.ts +60 -0
  273. package/src/brand-page/components/mailing-list/MailingList.mixin.test.ts +92 -0
  274. package/src/brand-page/components/mailing-list/MailingList.mixin.ts +28 -3
  275. package/src/brand-page/components/mailing-list/MailingList.vue +9 -4
  276. package/src/brand-page/components/mailing-list/MailingList.vue.test.ts +63 -0
  277. package/src/brand-page/components/navigation/button-carousel/ButtonCarouselNavigation.mixin.ts +51 -1
  278. package/src/brand-page/components/navigation/button-carousel/ButtonCarouselNavigation.test.ts +114 -0
  279. package/src/brand-page/components/navigation/button-carousel/ButtonCarouselNavigation.vue +8 -2
  280. package/src/brand-page/components/navigation/navigation-carousel/NavigationCarousel.test.ts +182 -0
  281. package/src/brand-page/components/navigation/navigation-carousel/NavigationCarousel.vue +59 -12
  282. package/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.ts +40 -3
  283. package/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.vue +15 -7
  284. package/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.vue.test.ts +133 -3
  285. package/src/brand-page/components/page/Page.mixin.ts +41 -34
  286. package/src/brand-page/components/page/Page.vue +17 -6
  287. package/src/brand-page/components/page/Page.vue.test.ts +91 -1
  288. package/src/brand-page/components/page-footer/PageFooter.mixin.ts +32 -2
  289. package/src/brand-page/components/page-footer/PageFooter.test.ts +79 -0
  290. package/src/brand-page/components/page-footer/PageFooter.vue +12 -4
  291. package/src/brand-page/components/payment/Payment.mixin.ts +34 -2
  292. package/src/brand-page/components/payment/Payment.test.ts +188 -0
  293. package/src/brand-page/components/payment/Payment.vue +12 -5
  294. package/src/brand-page/components/payment/RequestPaymentStripe.vue +1 -0
  295. package/src/brand-page/components/payment/support-me/SupportMe.mixin.ts +49 -2
  296. package/src/brand-page/components/payment/support-me/SupportMe.test.ts +100 -0
  297. package/src/brand-page/components/payment/support-me/SupportMe.vue +7 -1
  298. package/src/brand-page/components/payment/support-me/SupportMe.vue.test.ts +66 -0
  299. package/src/brand-page/components/save-contact/SaveContactWidget.test.ts +100 -0
  300. package/src/brand-page/components/save-contact/SaveContactWidget.vue +6 -3
  301. package/src/brand-page/components/shop/PaymentModal.vue +2 -6
  302. package/src/brand-page/components/shop/PaymentShippingAddress.vue +6 -0
  303. package/src/brand-page/components/shop/Shop.vue +15 -2
  304. package/src/brand-page/components/shop/Shop.vue.test.ts +74 -2
  305. package/src/brand-page/components/social-links/SocialLinks.stories.ts +0 -3
  306. package/src/brand-page/components/social-links/SocialLinks.vue.test.ts +0 -3
  307. package/src/brand-page/components/testimonial-section/__fixtures__/data.ts +0 -3
  308. package/src/brand-page/components/text/Text.stories.ts +0 -17
  309. package/src/brand-page/components/text-wrapper/TextWrapper.parity.test.ts +136 -0
  310. package/src/brand-page/components/text-wrapper/TextWrapper.test.ts +358 -0
  311. package/src/brand-page/components/text-wrapper/TextWrapper.vue +82 -22
  312. package/src/brand-page/constants/font.constants.ts +37 -0
  313. package/src/brand-page/models/footer-icon-color.test.ts +22 -0
  314. package/src/brand-page/models/index.ts +50 -28
  315. package/src/brand-page/models/navigation-styles.model.test.ts +77 -1
  316. package/src/brand-page/models/navigation-styles.model.ts +26 -9
  317. package/src/brand-page/models/payment.model.ts +15 -6
  318. package/src/brand-page/models/styles.model.test.ts +104 -0
  319. package/src/brand-page/models/styles.model.ts +181 -47
  320. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +619 -115
  321. package/src/brand-page/utils/__snapshots__/migration2.util.test.ts.snap +150 -9
  322. package/src/brand-page/utils/__snapshots__/model.util.test.ts.snap +300 -18
  323. package/src/brand-page/utils/color-palette.util.test.ts +126 -1
  324. package/src/brand-page/utils/color-palette.util.ts +92 -26
  325. package/src/brand-page/utils/color.util.test.ts +62 -29
  326. package/src/brand-page/utils/color.util.ts +77 -14
  327. package/src/brand-page/utils/container-text-color.util.test.ts +672 -26
  328. package/src/brand-page/utils/container-text-color.util.ts +472 -46
  329. package/src/brand-page/utils/index.ts +1 -0
  330. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/edited-brandsite-sections.v22.json +1191 -0
  331. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/new-brandcontact-every-section.v22.json +2026 -0
  332. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/new-brandpage-every-section.v22.json +2017 -0
  333. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/new-brandsite-every-section.v22.json +2031 -0
  334. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandcontact.v22.json +1145 -0
  335. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandpage-general-link.v22.json +645 -0
  336. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandpage-links.v22.json +1136 -0
  337. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandpage-social-links.v22.json +662 -0
  338. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandsite-about.v22.json +638 -0
  339. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandsite-footer.v22.json +610 -0
  340. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandsite-header-banner.v22.json +660 -0
  341. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandsite-sections.v22.json +1132 -0
  342. package/src/brand-page/utils/migration/migration-01.ts +293 -237
  343. package/src/brand-page/utils/migration/migration-02.ts +8 -1
  344. package/src/brand-page/utils/migration/migration-20.ts +6 -3
  345. package/src/brand-page/utils/migration/migration-20_5.test.ts +5 -2
  346. package/src/brand-page/utils/migration/migration-21.test.ts +34 -0
  347. package/src/brand-page/utils/migration/migration-21.ts +46 -10
  348. package/src/brand-page/utils/migration/migration-22.fixed-input.test.ts +43 -0
  349. package/src/brand-page/utils/migration/migration-22.test.ts +4103 -0
  350. package/src/brand-page/utils/migration/migration-22.text-font-family.test.ts +72 -0
  351. package/src/brand-page/utils/migration/migration-22.ts +1336 -0
  352. package/src/brand-page/utils/migration.util.test.ts +146 -32
  353. package/src/brand-page/utils/migration.util.ts +18 -0
  354. package/src/brand-page/utils/model.util.ts +4 -0
  355. package/src/brand-page/utils/personalisation.util.test.ts +148 -3
  356. package/src/brand-page/utils/personalisation.util.ts +9 -1
  357. package/src/brand-page/utils/rte-role-lift.util.ts +409 -0
  358. package/src/brand-page/utils/style.util.test.ts +35 -2
  359. package/src/brand-page/utils/style.util.ts +45 -11
  360. package/src/brand-page/utils/text-role-css.util.test.ts +525 -0
  361. package/src/brand-page/utils/text-role-css.util.ts +321 -0
  362. package/src/brand-page/utils/text-role-reconnect.util.test.ts +604 -0
  363. package/src/brand-page/utils/text-role-reconnect.util.ts +727 -0
  364. package/src/brand-page/utils/text-style.util.test.ts +305 -0
  365. package/src/brand-page/utils/text-style.util.ts +198 -24
  366. package/src/brand-page/utils/view-model.page-data.test.ts +232 -0
  367. package/src/brand-page/utils/view-model.util.test.ts +954 -133
  368. package/src/brand-page/utils/view-model.util.ts +187 -139
  369. package/src/brand-page/view-models.ts +4 -0
  370. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.blank-site.test.ts +57 -0
  371. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +9 -5
  372. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +0 -10
  373. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/content-settings-items.fixture.ts +0 -1
  374. package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.ts +0 -44
  375. package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +253 -200
  376. package/src/brand-page-maker/components/shop/AddOrEditProductContainer.vue +1 -0
  377. package/src/brand-page-maker/components/template-preview/TemplatePreview.vue +1 -0
  378. package/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.ts +2 -0
  379. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +1 -0
  380. package/src/brand-page-maker/composables/rich-text-editor/block-typography.test.ts +519 -0
  381. package/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.test.ts +1 -1
  382. package/src/brand-page-maker/composables/rich-text-editor/extensions/MaxLength.test.ts +26 -1
  383. package/src/brand-page-maker/composables/rich-text-editor/extensions/RoleTypographyFill.test.ts +110 -0
  384. package/src/brand-page-maker/composables/rich-text-editor/extensions/RoleTypographyFill.ts +99 -0
  385. package/src/brand-page-maker/composables/rich-text-editor/extensions/RteClipboard.ts +397 -0
  386. package/src/brand-page-maker/composables/rich-text-editor/extensions/ViewDomParser.test.ts +139 -0
  387. package/src/brand-page-maker/composables/rich-text-editor/font.ts +36 -5
  388. package/src/brand-page-maker/composables/rich-text-editor/formatting.test.ts +375 -1
  389. package/src/brand-page-maker/composables/rich-text-editor/formatting.ts +301 -17
  390. package/src/brand-page-maker/composables/rich-text-editor/hyperlink.test.ts +82 -1
  391. package/src/brand-page-maker/composables/rich-text-editor/hyperlink.ts +28 -34
  392. package/src/brand-page-maker/composables/rich-text-editor/keepMarksOnEmpty.test.ts +80 -0
  393. package/src/brand-page-maker/composables/rich-text-editor/keepMarksOnEmpty.ts +75 -0
  394. package/src/brand-page-maker/composables/rich-text-editor/spacing.ts +31 -6
  395. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.test.ts +2485 -0
  396. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +435 -337
  397. package/src/brand-page-maker/constants/config-settings-constant.ts +0 -6
  398. package/src/brand-page-maker/convertors/text-css-style-options.convertor.test.ts +43 -0
  399. package/src/brand-page-maker/convertors/text-css-style-options.convertor.ts +6 -2
  400. package/src/brand-page-maker/convertors/text-size-value.convertor.test.ts +24 -0
  401. package/src/brand-page-maker/convertors/text-size-value.convertor.ts +17 -13
  402. package/src/brand-page-maker/default-getters/payment-text-and-border-color.default-getter.ts +7 -22
  403. package/src/brand-page-maker/default-getters/text-color.default-getter.ts +5 -21
  404. package/src/brand-page-maker/models/content-settings.test.ts +708 -0
  405. package/src/brand-page-maker/models/content-settings.ts +133 -82
  406. package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store-utils.test.ts +63 -1
  407. package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store-utils.ts +16 -3
  408. package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store.test.ts +34 -0
  409. package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store.ts +4 -2
  410. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +185 -1
  411. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +22 -34
  412. package/src/brand-page-maker/stores/history/history-store.ts +35 -2
  413. package/src/brand-page-maker/utils/__snapshots__/apply-color-strategy.golden.test.ts.snap +528 -0
  414. package/src/brand-page-maker/utils/__snapshots__/rte-render-parity.test.ts.snap +12 -0
  415. package/src/brand-page-maker/utils/apply-color-strategy.golden.test.ts +2 -0
  416. package/src/brand-page-maker/utils/apply-color-strategy.test.ts +181 -3
  417. package/src/brand-page-maker/utils/apply-color-strategy.ts +36 -4
  418. package/src/brand-page-maker/utils/index.ts +2 -1
  419. package/src/brand-page-maker/utils/rich-text-editor.util.test.ts +447 -410
  420. package/src/brand-page-maker/utils/rich-text-editor.util.ts +610 -506
  421. package/src/brand-page-maker/utils/rte-authoring.util.test.ts +244 -0
  422. package/src/brand-page-maker/utils/rte-authoring.util.ts +175 -0
  423. package/src/brand-page-maker/utils/rte-clipboard.util.test.ts +558 -0
  424. package/src/brand-page-maker/utils/rte-clipboard.util.ts +473 -0
  425. package/src/brand-page-maker/utils/rte-features.test.ts +99 -3
  426. package/src/brand-page-maker/utils/rte-render-parity.test.ts +1 -1
  427. package/src/brand-page-maker/utils/rte-render.util.test.ts +230 -0
  428. package/src/brand-page-maker/utils/rte-sanitize-json.test.ts +1 -1
  429. package/src/brand-page-maker/utils/rte-sanitize.util.ts +14 -3
  430. package/src/brand-page-maker/utils/rte-schema-version.test.ts +102 -0
  431. package/src/bundles/bundled-translations.de-DE.json +21 -2
  432. package/src/bundles/bundled-translations.es-ES.json +21 -2
  433. package/src/bundles/bundled-translations.fr-CA.json +21 -2
  434. package/src/bundles/bundled-translations.fr-FR.json +21 -2
  435. package/src/bundles/bundled-translations.json +21 -2
  436. package/src/bundles/bundled-translations.pt-BR.json +21 -2
  437. package/src/bundles/bundled-translations.pt-PT.json +21 -2
  438. package/src/clients/ai-assistant-client.ts +1 -0
  439. package/src/composables/useTranslate.ts +2 -1
  440. package/src/lib.ts +2 -2
  441. package/src/metadata-builder/builders/footer-builder.test.ts +70 -45
  442. package/src/metadata-builder/builders/footer-builder.ts +4 -8
  443. package/src/metadata-builder/builders/global-role-propagation.test.ts +907 -0
  444. package/src/metadata-builder/builders/global-role-propagation.ts +430 -0
  445. package/src/metadata-builder/builders/global-styles-builder.test.ts +1020 -0
  446. package/src/metadata-builder/builders/global-styles-builder.ts +194 -48
  447. package/src/metadata-builder/builders/header-builder.test.ts +112 -40
  448. package/src/metadata-builder/builders/header-builder.ts +18 -8
  449. package/src/metadata-builder/builders/section-builders/about-section-builder.ts +5 -3
  450. package/src/metadata-builder/builders/section-builders/banner-section-builder.ts +5 -3
  451. package/src/metadata-builder/builders/section-builders/booking-section-builder.ts +5 -3
  452. package/src/metadata-builder/builders/section-builders/contact-form-builder.ts +7 -4
  453. package/src/metadata-builder/builders/section-builders/images-section-builder.ts +5 -3
  454. package/src/metadata-builder/builders/section-builders/mailing-list-builder.ts +3 -2
  455. package/src/metadata-builder/builders/section-builders/mailing-list-section-builder.ts +3 -2
  456. package/src/metadata-builder/builders/section-builders/profile-section-builder.ts +7 -7
  457. package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +5 -3
  458. package/src/metadata-builder/builders/section-builders/social-links-builder.test.ts +2 -2
  459. package/src/metadata-builder/builders/section-builders/social-links-builder.ts +21 -10
  460. package/src/metadata-builder/builders/section-builders/support-me-builder.test.ts +10 -0
  461. package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +3 -2
  462. package/src/metadata-builder/builders/section-builders/text-section-builder.ts +111 -61
  463. package/src/metadata-builder/builders/section-field-maps.ts +1 -0
  464. package/src/metadata-builder/builders/section-field-utils.test.ts +545 -2
  465. package/src/metadata-builder/builders/section-field-utils.ts +202 -69
  466. package/src/metadata-builder/builders/section-rules/global-styles.rules.ts +38 -13
  467. package/src/metadata-builder/builders/section-rules/social-links.rules.ts +5 -0
  468. package/src/metadata-builder/helpers/rte.helpers.test.ts +101 -0
  469. package/src/metadata-builder/helpers/rte.helpers.ts +129 -43
  470. package/src/metadata-builder/metadata-executor.test.ts +167 -0
  471. package/src/metadata-builder/metadata-executor.ts +34 -1
  472. package/src/metadata-builder/models.ts +2 -0
  473. package/src/metadata-builder/parsers/ai-toolcall-parser.ts +23 -7
  474. package/src/metadata-builder/parsers/section-tool-arguments.ts +21 -1
  475. package/src/metadata-builder/sanitizers/__tests__/section-args-validator.test.ts +215 -0
  476. package/src/metadata-builder/sanitizers/rte-schema-check.ts +1 -1
  477. package/src/metadata-builder/sanitizers/sanitizer-rules.ts +4 -8
  478. package/src/metadata-builder/sanitizers/section-args-validator.ts +136 -53
  479. package/src/shared/color-palette/section-color-matches.test.ts +15 -11
  480. package/src/shared/color-palette/section-color-matches.ts +9 -28
  481. package/src/shared/color-strategies/color-strategies.ts +35 -0
  482. package/src/shared/color-strategies/rte-color.test.ts +1 -1
  483. package/src/shared/color-strategies/rte-color.ts +19 -0
  484. package/src/shared/color-strategies/rte-field-pairs.test.ts +26 -5
  485. package/src/shared/color-strategies/rte-field-pairs.ts +33 -0
  486. package/src/shared/content-settings/components/color-matches-panel/ColorMatchesPanel.test.ts +43 -66
  487. package/src/shared/content-settings/components/color-matches-panel/ColorMatchesPanel.vue +7 -1
  488. package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +1 -48
  489. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +33 -7
  490. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.test.ts +128 -1
  491. package/src/shared/content-settings/components/draggable-item-list/DraggableItemList.vue +1 -0
  492. package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.ts +0 -6
  493. package/src/shared/content-settings/components/logo-selection-field/LogoSelection.vue +3 -0
  494. package/src/shared/content-settings/components/logo-size-field/LogoSizeSlider.vue +3 -0
  495. package/src/shared/content-settings/components/logo-size-field/LogoSizeSliderField.vue +1 -0
  496. package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.vue +1 -0
  497. package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.test.ts +56 -3
  498. package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.ts +11 -4
  499. package/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.test.ts +335 -25
  500. package/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.ts +248 -70
  501. package/src/shared/content-settings/components/text-style-field/TextStyleField.vue +113 -25
  502. package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.de-DE.json +17 -10
  503. package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.es-ES.json +17 -10
  504. package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.fr-CA.json +17 -10
  505. package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.fr-FR.json +17 -10
  506. package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.json +8 -1
  507. package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.pt-BR.json +17 -10
  508. package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.pt-PT.json +17 -10
  509. package/src/shared/content-settings/components/text-style-role-dropdown/TextStyleRoleDropdown.test.ts +141 -0
  510. package/src/shared/content-settings/components/text-style-role-dropdown/TextStyleRoleDropdown.vue +136 -0
  511. package/src/shared/content-settings/store/content-settings-store.test.ts +491 -6
  512. package/src/shared/content-settings/store/content-settings-store.ts +159 -17
  513. package/src/shared/logo-settings/components/EditLogoSettings.vue +1 -0
  514. package/src/shared/logo-settings/components/LogoVariations.vue +1 -0
  515. package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.vue +1 -0
  516. package/src/shared/navigation-style-settings/store/index.test.ts +295 -0
  517. package/src/shared/navigation-style-settings/store/index.ts +65 -15
  518. package/src/shared/page-settings/components/header-settings-panel/HeaderSettingsPanel.vue +2 -0
  519. package/src/shared/page-settings/components/page-settings/PageElement.vue +1 -0
  520. package/src/shared/page-settings/components/page-settings-section-styles/HeaderButtonSettings.test.ts +44 -4
  521. package/src/shared/page-settings/components/page-settings-section-styles/HeaderButtonSettings.vue +13 -4
  522. package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.navigation.test.ts +89 -0
  523. package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.text-style.test.ts +91 -0
  524. package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.ts +14 -2
  525. package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.vue +2 -0
  526. package/src/shared/page-settings/store/page-settings-store.text-style.test.ts +84 -0
  527. package/src/shared/page-settings/store/page-settings-store.ts +30 -1
  528. package/src/shared/rte-extensions/AutoLink.test.ts +98 -0
  529. package/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/AutoLink.ts +87 -58
  530. package/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/MaxLength.ts +4 -1
  531. package/src/shared/rte-extensions/TextEffects.ts +151 -0
  532. package/src/shared/rte-extensions/ViewDomParser.ts +27 -0
  533. package/src/{brand-page-maker/composables/rich-text-editor/getRteExtensions.ts → shared/rte-extensions.util.ts} +66 -9
  534. package/src/shared/rte-link.util.ts +2 -0
  535. package/src/shared/rte-render.util.ts +385 -0
  536. package/src/shared/rte-shape.util.ts +29 -0
  537. package/src/shared/side-bar/store/side-bar-store.test.ts +27 -1
  538. package/src/shared/side-bar/store/side-bar-store.ts +11 -0
  539. package/src/shared/style-settings/components/StyleSettings.mixin.ts +7 -3
  540. package/src/shared/style-settings/components/StyleSettings.test.ts +116 -0
  541. package/src/shared/style-settings/components/StyleSettings.vue +75 -25
  542. package/src/shared/style-settings/components/i18n/style-settings.de-DE.json +32 -20
  543. package/src/shared/style-settings/components/i18n/style-settings.es-ES.json +32 -20
  544. package/src/shared/style-settings/components/i18n/style-settings.fr-CA.json +32 -20
  545. package/src/shared/style-settings/components/i18n/style-settings.fr-FR.json +32 -20
  546. package/src/shared/style-settings/components/i18n/style-settings.json +13 -3
  547. package/src/shared/style-settings/components/i18n/style-settings.pt-BR.json +32 -20
  548. package/src/shared/style-settings/components/i18n/style-settings.pt-PT.json +32 -20
  549. package/src/shared/style-settings/components/text-style-options-settings-with-state/TextStyleOptionsSettingsWithState.vue +14 -34
  550. package/src/shared/style-settings/store/style-settings-store.ts +3 -49
  551. package/src/shared/style-settings/text-style-size-order.test.ts +76 -0
  552. package/src/shared/style-settings/text-style-size-order.ts +28 -0
  553. package/src/shared/template-settings/components/TemplatesSettings.vue +4 -0
  554. package/src/shared/text-role-typography.util.ts +277 -0
  555. package/src/utils/minify-brand-page-metadata.test.ts +102 -7
  556. package/src/utils/minify-brand-page-metadata.ts +62 -8
  557. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/AutoLink.d.ts +0 -2
  558. package/lib/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.d.ts +0 -28
  559. package/lib/src/brand-page-maker/utils/rte-render.util.d.ts +0 -63
  560. package/lib/src/brand-page-maker/utils/rte-render.util.js +0 -106
  561. package/lib/src/brand-page-maker/utils/rte-shape.d.ts +0 -18
  562. package/lib/src/brand-page-maker/utils/rte-shape.js +0 -21
  563. package/lib/src/metadata-builder/builders/global-font-propagation.d.ts +0 -41
  564. package/lib/src/metadata-builder/builders/global-font-propagation.js +0 -146
  565. package/src/brand-page-maker/utils/rte-render.util.ts +0 -179
  566. package/src/brand-page-maker/utils/rte-shape.ts +0 -29
  567. package/src/metadata-builder/builders/global-font-propagation.test.ts +0 -401
  568. package/src/metadata-builder/builders/global-font-propagation.ts +0 -238
  569. package/src/shared/style-settings/components/StyleSettingsSection.vue +0 -8
  570. /package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/FontFamily.d.ts +0 -0
  571. /package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/FontFamily.js +0 -0
  572. /package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/LetterSpacing.d.ts +0 -0
  573. /package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/LetterSpacing.js +0 -0
  574. /package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/MaxLength.d.ts +0 -0
  575. /package/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/FontFamily.ts +0 -0
  576. /package/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/LetterSpacing.ts +0 -0
@@ -3,6 +3,10 @@ import type { BrandPageModel } from '../../brand-page/models';
3
3
  import type { UpdateGlobalStylesArguments } from '../parsers/ai-toolcall-parser';
4
4
  import { BUILDER_TYPES } from '../models';
5
5
  import { GlobalStylesBuilder } from './global-styles-builder';
6
+ import {
7
+ roleTypographyStyle,
8
+ runTypographyFillValue,
9
+ } from '../../brand-page/utils/text-role-css.util';
6
10
 
7
11
  /**
8
12
  * BP-6082: for a button shape change the AI's update_global_styles carries only
@@ -105,3 +109,1019 @@ describe('GlobalStylesBuilder — button preset shape (BP-6082)', () => {
105
109
  );
106
110
  });
107
111
  });
112
+
113
+ // BP-5969 O2/T3.8 — a role is guaranteed to have a value (James Joung, "roles will now be
114
+ // guaranteed to have value"): the AI global-styles merge must never blank one. The pipeline's
115
+ // client turns a cleared field into `null` or `''`; either must be skipped, not written.
116
+ describe('GlobalStylesBuilder — never empties a role value (T3.8)', () => {
117
+ it('never empties a role value', async () => {
118
+ const model = {
119
+ styles: {
120
+ textStyles: {
121
+ textStyleOptions: {
122
+ heading2: {
123
+ style: {
124
+ fontSize: '2.25em',
125
+ lineHeight: '1.3',
126
+ fontFamily: 'Lato',
127
+ },
128
+ isModified: false,
129
+ },
130
+ },
131
+ },
132
+ },
133
+ } as unknown as BrandPageModel;
134
+
135
+ const { model: result } = await run(
136
+ {
137
+ textStyles: {
138
+ textStyleOptions: {
139
+ heading2: {
140
+ style: {
141
+ fontSize: '',
142
+ lineHeight: null as unknown as string,
143
+ fontFamily: 'Poppins',
144
+ },
145
+ },
146
+ },
147
+ },
148
+ },
149
+ model,
150
+ );
151
+ const ts = result.styles.textStyles.textStyleOptions as Record<
152
+ string,
153
+ { style: { fontSize?: string; lineHeight?: string; fontFamily?: string } }
154
+ >;
155
+
156
+ expect(ts.heading2.style.fontSize).toBe('2.25em');
157
+ expect(ts.heading2.style.lineHeight).toBe('1.3');
158
+ expect(ts.heading2.style.fontFamily).toBe('Poppins');
159
+ });
160
+ });
161
+
162
+ // BP-5969 (N1, re-review fix pass) — fontStyle/fontWeight/textDecoration/letterSpacing have a
163
+ // CSS-neutral default the role class always emits, so a cleared field for one of THESE is a
164
+ // genuine "turn it off": the property is written to that neutral, not deleted. Deleting it left
165
+ // the role object without the key, so `roleTypographyStyle` (which only refs a property the role
166
+ // object actually holds) emitted nothing for plain text — falling through to inherit whatever
167
+ // ancestor happened to set (`tw-font-semibold` on RequestPayment/shop text) — while a rich-text
168
+ // run still refs the class's neutral regardless, so plain and rich painted differently after an
169
+ // AI reset.
170
+ describe('GlobalStylesBuilder — a cleared neutral-backed property resets, not skips', () => {
171
+ it('a null fontStyle and an empty textDecoration clear to the role default, not the old value', async () => {
172
+ const model = {
173
+ styles: {
174
+ textStyles: {
175
+ textStyleOptions: {
176
+ heading2: {
177
+ style: {
178
+ fontSize: '2.25em',
179
+ fontStyle: 'italic',
180
+ textDecoration: 'underline',
181
+ },
182
+ isModified: false,
183
+ },
184
+ },
185
+ },
186
+ },
187
+ } as unknown as BrandPageModel;
188
+
189
+ const { model: result } = await run(
190
+ {
191
+ textStyles: {
192
+ textStyleOptions: {
193
+ heading2: {
194
+ style: {
195
+ fontStyle: null as unknown as string,
196
+ textDecoration: '',
197
+ },
198
+ },
199
+ },
200
+ },
201
+ },
202
+ model,
203
+ );
204
+ const ts = result.styles.textStyles.textStyleOptions as Record<
205
+ string,
206
+ {
207
+ style: {
208
+ fontSize?: string;
209
+ fontStyle?: string;
210
+ textDecoration?: string;
211
+ };
212
+ }
213
+ >;
214
+
215
+ expect(ts.heading2.style.fontStyle).toBe('normal');
216
+ expect(ts.heading2.style.textDecoration).toBe('none');
217
+ expect(ts.heading2.style.fontSize).toBe('2.25em');
218
+ });
219
+
220
+ it('an AI null reset leaves the role holding the neutral, so plain and rich text still agree', async () => {
221
+ const model = {
222
+ styles: {
223
+ textStyles: {
224
+ textStyleOptions: {
225
+ heading2: {
226
+ style: { fontSize: '2.25em', fontWeight: 'bold' },
227
+ isModified: false,
228
+ },
229
+ },
230
+ },
231
+ },
232
+ } as unknown as BrandPageModel;
233
+
234
+ const { model: result } = await run(
235
+ {
236
+ textStyles: {
237
+ textStyleOptions: {
238
+ heading2: { style: { fontWeight: null as unknown as string } },
239
+ },
240
+ },
241
+ },
242
+ model,
243
+ );
244
+ const ts = result.styles.textStyles.textStyleOptions as Record<
245
+ string,
246
+ { style: { fontSize?: string; fontWeight?: string } }
247
+ >;
248
+ const roleStyle = ts.heading2.style;
249
+
250
+ expect(Object.prototype.hasOwnProperty.call(roleStyle, 'fontWeight')).toBe(
251
+ true,
252
+ );
253
+ expect(roleStyle.fontWeight).toBe('normal');
254
+
255
+ // With the key held (not deleted), a plain-text painter sees the role define the property
256
+ // and references its var — the same reference a rich-text run always emits for a
257
+ // neutral-backed attr. Both resolve through the same class-level `--role-font-weight`, so
258
+ // an ancestor's own font-weight (e.g. a bold wrapper) can no longer leak through on one side
259
+ // only.
260
+ expect(roleTypographyStyle({}, roleStyle).fontWeight).toBe(
261
+ 'var(--role-font-weight)',
262
+ );
263
+ expect(runTypographyFillValue('fontWeight', roleStyle, undefined)).toBe(
264
+ 'var(--role-font-weight)',
265
+ );
266
+ });
267
+
268
+ it('accepts a stored normal letter spacing and still applies other global styles', async () => {
269
+ const model = {
270
+ styles: {
271
+ backgroundStyles: { style: { background: '#ffffff' } },
272
+ buttonStyles: {
273
+ style: {},
274
+ iconStyle: {},
275
+ selectedButtonStyleId: 'BUTTON_STYLE_4',
276
+ },
277
+ textStyles: {
278
+ textStyleOptions: {
279
+ heading2: {
280
+ style: { fontSize: '2.25em', letterSpacing: '0.1em' },
281
+ isModified: false,
282
+ },
283
+ },
284
+ },
285
+ },
286
+ } as unknown as BrandPageModel;
287
+
288
+ const cleared = await run(
289
+ {
290
+ textStyles: {
291
+ textStyleOptions: {
292
+ heading2: { style: { letterSpacing: null as unknown as string } },
293
+ },
294
+ },
295
+ },
296
+ model,
297
+ );
298
+ const { model: result, errors } = await run(
299
+ {
300
+ backgroundStyles: { backgroundColor: '#111111' },
301
+ buttonStyles: { style: { backgroundColor: '#222222' } },
302
+ textStyles: {
303
+ textStyleOptions: {
304
+ heading2: { style: { letterSpacing: 'normal' } },
305
+ },
306
+ },
307
+ },
308
+ cleared.model,
309
+ );
310
+
311
+ expect(errors).toBeUndefined();
312
+ expect(
313
+ result.styles.textStyles.textStyleOptions.heading2.style.letterSpacing,
314
+ ).toBe('normal');
315
+ expect(result.styles.backgroundStyles.style.background).toBe('#111111');
316
+ expect(result.styles.buttonStyles.style.backgroundColor).toBe('#222222');
317
+ });
318
+ });
319
+
320
+ // BP-5969 T6.1 — the baseline canonical-role merge (unchanged by Phase 6's retired-key rework):
321
+ // a v22+ model's own canonical role merges directly, is marked modified, and every legacy slot
322
+ // (still present, hidden) is left exactly as it was.
323
+ describe('GlobalStylesBuilder — canonical role merge (T6.1)', () => {
324
+ it('a v22 model merges heading2.style.fontFamily onto heading2, marks it modified, legacy untouched', async () => {
325
+ const model = {
326
+ styles: {
327
+ textStyles: {
328
+ textStyleOptions: {
329
+ heading2: { style: { fontFamily: 'Lato' }, isModified: false },
330
+ headings: { style: { fontFamily: 'Lato' }, isModified: false },
331
+ },
332
+ },
333
+ },
334
+ } as unknown as BrandPageModel;
335
+
336
+ const { model: result } = await run(
337
+ {
338
+ textStyles: {
339
+ textStyleOptions: { heading2: { style: { fontFamily: 'Oswald' } } },
340
+ },
341
+ },
342
+ model,
343
+ );
344
+ const ts = result.styles.textStyles.textStyleOptions as Record<
345
+ string,
346
+ { style: { fontFamily?: string }; isModified: boolean }
347
+ >;
348
+
349
+ expect(ts.heading2.style.fontFamily).toBe('Oswald');
350
+ expect(ts.heading2.isModified).toBe(true);
351
+ expect(ts.headings.style.fontFamily).toBe('Lato');
352
+ expect(ts.headings.isModified).toBe(false);
353
+ });
354
+ });
355
+
356
+ // BP-5969 R17 — role definitions (textStyleOptions) stay literal-only: a var(...) ref there is
357
+ // rejected, unlike the same attr on an RTE mark (section-args-validator's role-var exemption).
358
+ describe('GlobalStylesBuilder — validateAsync (R17 role definitions stay literal)', () => {
359
+ const validate = (args: UpdateGlobalStylesArguments) =>
360
+ new GlobalStylesBuilder({
361
+ id: 'g1',
362
+ type: BUILDER_TYPES.UPDATE_GLOBAL_STYLES,
363
+ payload: args,
364
+ }).validateAsync();
365
+
366
+ it('errors when a role definition carries a var(--role-...) ref', async () => {
367
+ const { errors } = await validate({
368
+ textStyles: {
369
+ textStyleOptions: {
370
+ heading2: { style: { fontSize: 'var(--role-font-size)' } },
371
+ },
372
+ },
373
+ });
374
+
375
+ expect(errors).toHaveLength(1);
376
+ expect(errors[0]).toMatch(/fontSize/);
377
+ });
378
+
379
+ it('passes a literal role definition', async () => {
380
+ const { errors } = await validate({
381
+ textStyles: {
382
+ textStyleOptions: { heading2: { style: { fontSize: '2.5em' } } },
383
+ },
384
+ });
385
+
386
+ expect(errors).toHaveLength(0);
387
+ });
388
+
389
+ it('errors when keepRuns carries a non-string entry (R16)', async () => {
390
+ const { errors } = await validate({
391
+ textStyles: { keepRuns: ['Taste', 42 as unknown as string] },
392
+ });
393
+
394
+ expect(errors).toHaveLength(1);
395
+ expect(errors[0]).toMatch(/keepRuns/);
396
+ });
397
+
398
+ it('passes a valid keepRuns array', async () => {
399
+ const { errors } = await validate({
400
+ textStyles: { keepRuns: ['Taste'] },
401
+ });
402
+
403
+ expect(errors).toHaveLength(0);
404
+ });
405
+ });
406
+
407
+ // BP-5969 R7 — a retired global key maps onto its successor role(s), not a hidden option.
408
+ describe('GlobalStylesBuilder — retired global key mapping (R7)', () => {
409
+ const HEADING_TIERS = [
410
+ 'heading1',
411
+ 'heading2',
412
+ 'heading3',
413
+ 'heading4',
414
+ 'heading5',
415
+ 'heading6',
416
+ ] as const;
417
+
418
+ const makeRoleModel = () => {
419
+ const textStyleOptions: Record<string, unknown> = {
420
+ titles: { style: { fontFamily: 'Lato', fontSize: '2.25em' } },
421
+ headings: { style: { fontFamily: 'Lato', fontSize: '1.5em' } },
422
+ paragraphs: { style: { fontFamily: 'Lato', fontSize: '1em' } },
423
+ buttons: { style: { fontFamily: 'Lato', fontSize: '1em' } },
424
+ };
425
+
426
+ for (const tier of HEADING_TIERS) {
427
+ textStyleOptions[tier] = { style: { fontFamily: 'Lato' } };
428
+ }
429
+
430
+ for (const tier of ['paragraph1', 'paragraph2', 'paragraph3', 'button']) {
431
+ textStyleOptions[tier] = { style: { fontFamily: 'Lato' } };
432
+ }
433
+
434
+ return {
435
+ styles: { textStyles: { textStyleOptions } },
436
+ pages: [],
437
+ } as unknown as BrandPageModel;
438
+ };
439
+
440
+ it('a retired "headings" family lands on heading2–heading6; the hidden slot is untouched', async () => {
441
+ const model = makeRoleModel();
442
+ const { model: result } = await run(
443
+ {
444
+ textStyles: {
445
+ textStyleOptions: { headings: { style: { fontFamily: 'Oswald' } } },
446
+ },
447
+ },
448
+ model,
449
+ );
450
+ const ts = result.styles.textStyles.textStyleOptions as Record<
451
+ string,
452
+ { style: { fontFamily?: string } }
453
+ >;
454
+
455
+ expect(ts.heading1.style.fontFamily).toBe('Lato');
456
+
457
+ for (const tier of [
458
+ 'heading2',
459
+ 'heading3',
460
+ 'heading4',
461
+ 'heading5',
462
+ 'heading6',
463
+ ]) {
464
+ expect(ts[tier].style.fontFamily).toBe('Oswald');
465
+ }
466
+
467
+ // hidden legacy slot: never written
468
+ expect(ts.headings.style.fontFamily).toBe('Lato');
469
+ });
470
+
471
+ it('a retired "titles" size lands on only the computeLegacyTargets titles tier', async () => {
472
+ const model = makeRoleModel();
473
+ const { model: result } = await run(
474
+ {
475
+ textStyles: {
476
+ textStyleOptions: { titles: { style: { fontSize: '3em' } } },
477
+ },
478
+ },
479
+ model,
480
+ );
481
+ const ts = result.styles.textStyles.textStyleOptions as Record<
482
+ string,
483
+ { style: { fontSize?: string } }
484
+ >;
485
+ const touched = HEADING_TIERS.filter(
486
+ (tier) => ts[tier].style.fontSize === '3em',
487
+ );
488
+
489
+ expect(touched).toHaveLength(1);
490
+ // hidden legacy slot: never written (still its original size)
491
+ expect(ts.titles.style.fontSize).toBe('2.25em');
492
+ });
493
+
494
+ it('a retired "headings" fontSize lands on only the computeLegacyTargets headings tier, not every h2–h6 (T7.3)', async () => {
495
+ const model = makeRoleModel();
496
+ const { model: result } = await run(
497
+ {
498
+ textStyles: {
499
+ textStyleOptions: { headings: { style: { fontSize: '2em' } } },
500
+ },
501
+ },
502
+ model,
503
+ );
504
+ const ts = result.styles.textStyles.textStyleOptions as Record<
505
+ string,
506
+ { style: { fontSize?: string } }
507
+ >;
508
+ const touched = HEADING_TIERS.filter(
509
+ (tier) => ts[tier].style.fontSize === '2em',
510
+ );
511
+
512
+ expect(touched).toHaveLength(1);
513
+ expect(ts.headings.style.fontSize).toBe('1.5em');
514
+ });
515
+
516
+ it('a retired "paragraphs" fontSize lands on only its one tier; a family change still reaches every paragraph tier', async () => {
517
+ const model = makeRoleModel();
518
+ const { model: result } = await run(
519
+ {
520
+ textStyles: {
521
+ textStyleOptions: {
522
+ paragraphs: { style: { fontSize: '1.2em', fontFamily: 'Oswald' } },
523
+ },
524
+ },
525
+ },
526
+ model,
527
+ );
528
+ const ts = result.styles.textStyles.textStyleOptions as Record<
529
+ string,
530
+ { style: { fontSize?: string; fontFamily?: string } }
531
+ >;
532
+ const sizeTouched = (
533
+ ['paragraph1', 'paragraph2', 'paragraph3'] as const
534
+ ).filter((tier) => ts[tier].style.fontSize === '1.2em');
535
+
536
+ expect(sizeTouched).toHaveLength(1);
537
+
538
+ for (const tier of ['paragraph1', 'paragraph2', 'paragraph3'] as const) {
539
+ expect(ts[tier].style.fontFamily).toBe('Oswald');
540
+ }
541
+
542
+ expect(ts.paragraphs.style.fontSize).toBe('1em'); // hidden slot untouched
543
+ });
544
+ });
545
+
546
+ // BP-5969 R10 (ADR-0020) — a role is typography only; colour never persists onto a definition.
547
+ describe('GlobalStylesBuilder — role definition stores no colour (R10)', () => {
548
+ it('a colour sent on a canonical role is dropped; its typography still merges', async () => {
549
+ const model = {
550
+ styles: {
551
+ textStyles: {
552
+ textStyleOptions: {
553
+ heading2: { style: { fontFamily: 'Lato' }, isModified: false },
554
+ },
555
+ },
556
+ },
557
+ pages: [],
558
+ } as unknown as BrandPageModel;
559
+
560
+ const {
561
+ model: result,
562
+ errors,
563
+ warnings,
564
+ } = await run(
565
+ {
566
+ textStyles: {
567
+ textStyleOptions: {
568
+ heading2: { style: { color: '#222222', fontFamily: 'Oswald' } },
569
+ },
570
+ },
571
+ },
572
+ model,
573
+ );
574
+ const heading2 = (
575
+ result.styles.textStyles.textStyleOptions as unknown as Record<
576
+ string,
577
+ { style: Record<string, unknown> }
578
+ >
579
+ ).heading2.style;
580
+
581
+ expect(errors ?? []).toEqual([]);
582
+ expect(warnings).toEqual([
583
+ 'Ignored role color for heading2; apply colour to the affected sections instead.',
584
+ ]);
585
+ expect(heading2.color).toBeUndefined();
586
+ expect(heading2.fontFamily).toBe('Oswald');
587
+ });
588
+ });
589
+
590
+ // BP-5969 R21 — the global styles builder validates before it mutates anything (the GAP: buildAsync
591
+ // never called its own validateAsync, so an invalid role value was stored unchecked).
592
+ describe('GlobalStylesBuilder — buildAsync validates before mutating (R21)', () => {
593
+ it('an invalid role fontSize returns the error and leaves the model untouched; no propagation runs', async () => {
594
+ const model = {
595
+ styles: {
596
+ textStyles: {
597
+ textStyleOptions: {
598
+ heading2: { style: { fontFamily: 'Lato' }, isModified: false },
599
+ },
600
+ },
601
+ },
602
+ pages: [
603
+ {
604
+ id: 'p1',
605
+ contents: [
606
+ {
607
+ id: 'c1',
608
+ type: 'about-section',
609
+ title: 'x',
610
+ titleStyle: { textStyleType: 'heading2', fontFamily: 'Lato' },
611
+ },
612
+ ],
613
+ },
614
+ ],
615
+ } as unknown as BrandPageModel;
616
+ const before = JSON.stringify(model);
617
+
618
+ const { model: result, errors } = await run(
619
+ {
620
+ textStyles: {
621
+ textStyleOptions: { heading2: { style: { fontSize: '20em' } } },
622
+ },
623
+ },
624
+ model,
625
+ );
626
+
627
+ expect(errors).toBeDefined();
628
+ expect(errors!.length).toBeGreaterThan(0);
629
+ expect(JSON.stringify(result)).toBe(before);
630
+ });
631
+
632
+ // B5 — a role's fontWeight/fontStyle/textDecoration is written verbatim into a page-level SSR
633
+ // <style> block (text-role-css.util.ts roleDeclarations), so an unvalidated value is a
634
+ // stored-XSS sink. An attempted CSS-breakout value must be rejected like any other bad input.
635
+ it('rejects an unrecognized fontWeight/fontStyle/textDecoration value (B5)', async () => {
636
+ const model = {
637
+ styles: { textStyles: { textStyleOptions: {} } },
638
+ pages: [{ id: 'p1', contents: [] }],
639
+ } as unknown as BrandPageModel;
640
+ const before = JSON.stringify(model);
641
+
642
+ const { errors: weightErrors } = await run(
643
+ {
644
+ textStyles: {
645
+ textStyleOptions: {
646
+ heading2: {
647
+ style: { fontWeight: '700}</style><script>alert(1)</script>' },
648
+ },
649
+ },
650
+ },
651
+ },
652
+ model,
653
+ );
654
+
655
+ expect(weightErrors).toBeDefined();
656
+ expect(weightErrors!.length).toBeGreaterThan(0);
657
+
658
+ const { errors: styleErrors } = await run(
659
+ {
660
+ textStyles: {
661
+ textStyleOptions: {
662
+ heading2: { style: { fontStyle: 'normal; } body { display:none' } },
663
+ },
664
+ },
665
+ },
666
+ model,
667
+ );
668
+
669
+ expect(styleErrors).toBeDefined();
670
+ expect(styleErrors!.length).toBeGreaterThan(0);
671
+
672
+ const { errors: decorationErrors } = await run(
673
+ {
674
+ textStyles: {
675
+ textStyleOptions: {
676
+ heading2: { style: { textDecoration: 'none}</style>' } },
677
+ },
678
+ },
679
+ },
680
+ model,
681
+ );
682
+
683
+ expect(decorationErrors).toBeDefined();
684
+ expect(decorationErrors!.length).toBeGreaterThan(0);
685
+ expect(JSON.stringify(model)).toBe(before);
686
+ });
687
+
688
+ it('accepts a recognized fontWeight/fontStyle/textDecoration value', async () => {
689
+ const model = {
690
+ styles: { textStyles: { textStyleOptions: {} } },
691
+ pages: [{ id: 'p1', contents: [] }],
692
+ } as unknown as BrandPageModel;
693
+
694
+ const { errors } = await run(
695
+ {
696
+ textStyles: {
697
+ textStyleOptions: {
698
+ heading2: {
699
+ style: {
700
+ fontWeight: 'bold',
701
+ fontStyle: 'italic',
702
+ textDecoration: 'underline',
703
+ },
704
+ },
705
+ },
706
+ },
707
+ },
708
+ model,
709
+ );
710
+
711
+ expect(errors ?? []).toEqual([]);
712
+ });
713
+
714
+ // The maker's strike + underline toggles compose text-decoration (formatting.ts's
715
+ // decorationSet/composeDecoration), and the role-lift migration of a legacy <u><s> run does the
716
+ // same (rte-role-lift.util.ts) — so a role definition must accept the combined value, not just a
717
+ // single keyword (N1).
718
+ it('accepts a combined text-decoration value ("underline line-through") the product itself writes (N1)', async () => {
719
+ const model = {
720
+ styles: { textStyles: { textStyleOptions: {} } },
721
+ pages: [{ id: 'p1', contents: [] }],
722
+ } as unknown as BrandPageModel;
723
+
724
+ const { errors } = await run(
725
+ {
726
+ textStyles: {
727
+ textStyleOptions: {
728
+ heading2: { style: { textDecoration: 'underline line-through' } },
729
+ },
730
+ },
731
+ },
732
+ model,
733
+ );
734
+
735
+ expect(errors ?? []).toEqual([]);
736
+ });
737
+
738
+ // The pipeline may emit a bare JSON number for an enum-checked attr; a prior fix-pass regression
739
+ // made that throw inside the check's own `.trim()` call, hitting the section path's fail-OPEN
740
+ // bug (base-section-builder.ts) and the global path's opaque "failed unexpectedly" error (N3).
741
+ it('accepts a bare numeric fontWeight instead of throwing on .trim() (N3)', async () => {
742
+ const model = {
743
+ styles: { textStyles: { textStyleOptions: {} } },
744
+ pages: [{ id: 'p1', contents: [] }],
745
+ } as unknown as BrandPageModel;
746
+
747
+ const { errors } = await run(
748
+ {
749
+ textStyles: {
750
+ textStyleOptions: {
751
+ heading2: { style: { fontWeight: 700 as unknown as string } },
752
+ },
753
+ },
754
+ },
755
+ model,
756
+ );
757
+
758
+ expect(errors ?? []).toEqual([]);
759
+ });
760
+
761
+ it('canonicalises a bare numeric lineHeight the same as a non-canonical string spelling (N3)', async () => {
762
+ const model = {
763
+ styles: {
764
+ textStyles: {
765
+ textStyleOptions: {
766
+ heading2: { style: { fontFamily: 'Lato' }, isModified: false },
767
+ },
768
+ },
769
+ },
770
+ pages: [{ id: 'p1', contents: [] }],
771
+ } as unknown as BrandPageModel;
772
+
773
+ const { model: result, errors } = await run(
774
+ {
775
+ textStyles: {
776
+ textStyleOptions: {
777
+ heading2: { style: { lineHeight: 1 as unknown as string } },
778
+ },
779
+ },
780
+ },
781
+ model,
782
+ );
783
+
784
+ expect(errors ?? []).toEqual([]);
785
+ expect(
786
+ (
787
+ result.styles!.textStyles!.textStyleOptions as unknown as Record<
788
+ string,
789
+ { style: Record<string, unknown> }
790
+ >
791
+ ).heading2.style.lineHeight,
792
+ ).toBe('1');
793
+ });
794
+
795
+ // R3 — a stored number never strictly equals a block's string '700' (runTypographyFillValue's
796
+ // `!==` comparison), so a role fontWeight must be canonicalised to its string form too.
797
+ it('stores a bare numeric fontWeight as its string form (R3)', async () => {
798
+ const model = {
799
+ styles: {
800
+ textStyles: {
801
+ textStyleOptions: {
802
+ heading2: { style: { fontFamily: 'Lato' }, isModified: false },
803
+ },
804
+ },
805
+ },
806
+ pages: [{ id: 'p1', contents: [] }],
807
+ } as unknown as BrandPageModel;
808
+
809
+ const { model: result, errors } = await run(
810
+ {
811
+ textStyles: {
812
+ textStyleOptions: {
813
+ heading2: { style: { fontWeight: 700 as unknown as string } },
814
+ },
815
+ },
816
+ },
817
+ model,
818
+ );
819
+
820
+ expect(errors ?? []).toEqual([]);
821
+ expect(
822
+ (
823
+ result.styles!.textStyles!.textStyleOptions as unknown as Record<
824
+ string,
825
+ { style: Record<string, unknown> }
826
+ >
827
+ ).heading2.style.fontWeight,
828
+ ).toBe('700');
829
+ });
830
+
831
+ // S4 — the pipeline's own tool docs showed a "1.0" example; the validator's spelling check
832
+ // (shared with strict RTE mark validation, R17) would otherwise reject it and drop the whole
833
+ // call. The library canonicalises a role's lineHeight spelling before validating, in place, so
834
+ // the stored value ends up canonical too — not just this one check.
835
+ it('canonicalises a non-canonical lineHeight spelling before validating (S4)', async () => {
836
+ const model = {
837
+ styles: {
838
+ textStyles: {
839
+ textStyleOptions: {
840
+ heading2: { style: { fontFamily: 'Lato' }, isModified: false },
841
+ },
842
+ },
843
+ },
844
+ pages: [{ id: 'p1', contents: [] }],
845
+ } as unknown as BrandPageModel;
846
+
847
+ const { model: result, errors } = await run(
848
+ {
849
+ textStyles: {
850
+ textStyleOptions: { heading2: { style: { lineHeight: '1.0' } } },
851
+ },
852
+ },
853
+ model,
854
+ );
855
+
856
+ expect(errors ?? []).toEqual([]);
857
+ expect(
858
+ (
859
+ result.styles!.textStyles!.textStyleOptions as unknown as Record<
860
+ string,
861
+ { style: Record<string, unknown> }
862
+ >
863
+ ).heading2.style.lineHeight,
864
+ ).toBe('1');
865
+ });
866
+
867
+ it('does not mutate numeric or non-canonical role values during validation', async () => {
868
+ const payload = {
869
+ textStyles: {
870
+ textStyleOptions: {
871
+ heading2: {
872
+ style: {
873
+ lineHeight: '1.0',
874
+ fontWeight: 700 as unknown as string,
875
+ },
876
+ },
877
+ },
878
+ },
879
+ } as UpdateGlobalStylesArguments;
880
+ const builder = new GlobalStylesBuilder({
881
+ id: 'g1',
882
+ type: BUILDER_TYPES.UPDATE_GLOBAL_STYLES,
883
+ payload,
884
+ });
885
+
886
+ expect((await builder.validateAsync()).errors).toEqual([]);
887
+ expect(payload.textStyles!.textStyleOptions!.heading2!.style).toEqual({
888
+ lineHeight: '1.0',
889
+ fontWeight: 700,
890
+ });
891
+ });
892
+
893
+ // S3 — a throwing check used to be swallowed as "no errors" (every check skipped, not just the
894
+ // one that threw), so a value with an unexpected runtime shape sailed through unvalidated.
895
+ it('fails closed when a check throws instead of silently accepting the call (S3)', async () => {
896
+ const model = {
897
+ styles: { textStyles: { textStyleOptions: {} } },
898
+ pages: [{ id: 'p1', contents: [] }],
899
+ } as unknown as BrandPageModel;
900
+ const before = JSON.stringify(model);
901
+
902
+ // fontSize is typed as a string; a runtime number throws inside the check's .trim() call.
903
+ const { errors } = await run(
904
+ {
905
+ textStyles: {
906
+ textStyleOptions: {
907
+ heading2: { style: { fontSize: 20 as unknown as string } },
908
+ },
909
+ },
910
+ },
911
+ model,
912
+ );
913
+
914
+ expect(errors).toBeDefined();
915
+ expect(errors!.length).toBeGreaterThan(0);
916
+ expect(JSON.stringify(model)).toBe(before);
917
+ });
918
+ });
919
+
920
+ // The pipeline sends full role patches. Propagating an unchanged field would turn a colour-only
921
+ // request into a site-wide restyle and erase intentional literal accents.
922
+ describe('GlobalStylesBuilder — an unchanged resend keeps literal overrides', () => {
923
+ it('does not relink an existing Oswald literal when the role already has Oswald', async () => {
924
+ const model = {
925
+ styles: {
926
+ textStyles: {
927
+ textStyleOptions: {
928
+ heading2: { style: { fontFamily: 'Oswald' }, isModified: false },
929
+ },
930
+ },
931
+ },
932
+ pages: [
933
+ {
934
+ id: 'p1',
935
+ contents: [
936
+ {
937
+ id: 'c1',
938
+ type: 'about-section',
939
+ title: 'Fine Grooming',
940
+ titleStyle: { textStyleType: 'heading2', fontFamily: 'Oswald' },
941
+ },
942
+ ],
943
+ },
944
+ ],
945
+ } as unknown as BrandPageModel;
946
+
947
+ const { model: result, errors } = await run(
948
+ {
949
+ textStyles: {
950
+ textStyleOptions: { heading2: { style: { fontFamily: 'Oswald' } } },
951
+ },
952
+ },
953
+ model,
954
+ );
955
+
956
+ const titleStyle = (
957
+ result.pages[0].contents[0] as unknown as Record<
958
+ string,
959
+ Record<string, unknown>
960
+ >
961
+ ).titleStyle;
962
+
963
+ expect(errors ?? []).toEqual([]);
964
+ expect(titleStyle.fontFamily).toBe('Oswald');
965
+ });
966
+ });
967
+
968
+ // The pipeline sends weight, style and decoration only when the user asked, so each relinks the
969
+ // role's existing content even when it equals the stored role.
970
+ describe('GlobalStylesBuilder — emphasis reaches existing content (BP-5969)', () => {
971
+ const rteDoc = (runs: { text: string; marks?: unknown[] }[]) => ({
972
+ type: 'doc',
973
+ content: [
974
+ {
975
+ type: 'paragraph',
976
+ content: runs.map((r) => ({ type: 'text', ...r })),
977
+ },
978
+ ],
979
+ });
980
+
981
+ type Run = {
982
+ text: string;
983
+ marks?: { type: string; attrs?: Record<string, unknown> }[];
984
+ };
985
+
986
+ const runsOf = (doc: unknown): Run[] =>
987
+ (doc as { content: { content: Run[] }[] }).content[0].content;
988
+
989
+ const emptyModel = () =>
990
+ ({
991
+ styles: { textStyles: { textStyleOptions: {} } },
992
+ pages: [{ id: 'p1', contents: [] }],
993
+ }) as unknown as BrandPageModel;
994
+
995
+ it.each([
996
+ { fontWeight: 'bold', fontStyle: 'italic', textDecoration: 'underline' },
997
+ { fontWeight: 'normal', fontStyle: 'normal', textDecoration: 'none' },
998
+ { textDecoration: 'line-through' },
999
+ { textDecoration: 'underline line-through' },
1000
+ { textDecoration: 'underline ' },
1001
+ { textDecoration: 'underline line-through ' },
1002
+ ])('accepts %o', async (style) => {
1003
+ const { errors } = await run(
1004
+ { textStyles: { textStyleOptions: { heading2: { style } } } },
1005
+ emptyModel(),
1006
+ );
1007
+
1008
+ expect(errors ?? []).toEqual([]);
1009
+ });
1010
+
1011
+ it('heading2 fontStyle italic relinks a pinned literal and drops the italic marks', async () => {
1012
+ const model = {
1013
+ styles: {
1014
+ textStyles: {
1015
+ textStyleOptions: {
1016
+ heading2: { style: { fontStyle: 'normal' }, isModified: false },
1017
+ },
1018
+ },
1019
+ },
1020
+ pages: [
1021
+ {
1022
+ id: 'p1',
1023
+ contents: [
1024
+ {
1025
+ id: 'c1',
1026
+ type: 'about-section',
1027
+ title: rteDoc([
1028
+ {
1029
+ text: 'Our ',
1030
+ marks: [
1031
+ { type: 'textStyle', attrs: { fontStyle: 'normal' } },
1032
+ ],
1033
+ },
1034
+ { text: 'Story', marks: [{ type: 'italic' }] },
1035
+ ]),
1036
+ titleStyle: { textStyleType: 'heading2', fontStyle: 'normal' },
1037
+ },
1038
+ ],
1039
+ },
1040
+ ],
1041
+ } as unknown as BrandPageModel;
1042
+
1043
+ const { model: result, errors } = await run(
1044
+ {
1045
+ textStyles: {
1046
+ textStyleOptions: { heading2: { style: { fontStyle: 'italic' } } },
1047
+ },
1048
+ },
1049
+ model,
1050
+ );
1051
+ const content = result.pages[0].contents[0] as unknown as Record<
1052
+ string,
1053
+ unknown
1054
+ >;
1055
+ const [our, story] = runsOf(content.title);
1056
+
1057
+ expect(errors ?? []).toEqual([]);
1058
+ expect(
1059
+ result.styles.textStyles.textStyleOptions.heading2.style.fontStyle,
1060
+ ).toBe('italic');
1061
+ expect(our.marks).toEqual([
1062
+ { type: 'textStyle', attrs: { fontStyle: 'var(--role-font-style)' } },
1063
+ ]);
1064
+ expect(story.marks).toEqual([]);
1065
+ expect(content.titleStyle).toEqual({ textStyleType: 'heading2' });
1066
+ });
1067
+
1068
+ it('button textDecoration none clears the button underline while a paragraph link keeps its own', async () => {
1069
+ const linkRun = {
1070
+ text: 'our menu',
1071
+ marks: [
1072
+ { type: 'link', attrs: { href: 'https://example.com' } },
1073
+ { type: 'underline' },
1074
+ ],
1075
+ };
1076
+ const model = {
1077
+ styles: {
1078
+ textStyles: {
1079
+ textStyleOptions: {
1080
+ button: { style: { textDecoration: 'none' }, isModified: false },
1081
+ paragraph1: { style: {}, isModified: false },
1082
+ },
1083
+ },
1084
+ },
1085
+ pages: [
1086
+ {
1087
+ id: 'p1',
1088
+ contents: [
1089
+ {
1090
+ id: 'c1',
1091
+ type: 'about-section',
1092
+ description: rteDoc([{ text: 'See ' }, linkRun]),
1093
+ descriptionStyle: { textStyleType: 'paragraph1' },
1094
+ buttonText: 'Book now',
1095
+ buttonTextStyle: {
1096
+ textStyleType: 'button',
1097
+ textDecoration: 'underline',
1098
+ },
1099
+ },
1100
+ ],
1101
+ },
1102
+ ],
1103
+ } as unknown as BrandPageModel;
1104
+
1105
+ const { model: result, errors } = await run(
1106
+ {
1107
+ textStyles: {
1108
+ textStyleOptions: {
1109
+ button: { style: { textDecoration: 'none' } },
1110
+ },
1111
+ },
1112
+ },
1113
+ model,
1114
+ );
1115
+ const content = result.pages[0].contents[0] as unknown as Record<
1116
+ string,
1117
+ unknown
1118
+ >;
1119
+
1120
+ expect(errors ?? []).toEqual([]);
1121
+ expect(content.buttonTextStyle).toEqual({ textStyleType: 'button' });
1122
+ expect(runsOf(content.description)[1]).toEqual({
1123
+ type: 'text',
1124
+ ...linkRun,
1125
+ });
1126
+ });
1127
+ });