@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
@@ -1,20 +1,28 @@
1
1
  import { onBeforeUnmount, computed, watch, } from 'vue';
2
2
  import { Editor } from '@tiptap/vue-3';
3
- import { getRteExtensions } from './getRteExtensions';
3
+ import { getRteExtensions } from '@shared/rte-extensions.util';
4
+ import { KeepMarksOnEmpty, keepMarksOnEmptyPluginKey, } from './keepMarksOnEmpty';
5
+ import { RoleTypographyFill } from './extensions/RoleTypographyFill';
6
+ import { RteClipboard } from './extensions/RteClipboard';
4
7
  import { createFormattingActions } from './formatting';
5
8
  import { useTextAlign } from './textAlign';
6
9
  import { useFont } from './font';
7
10
  import { useSpacing } from './spacing';
8
- import { buildInitialMarks, emToPx, isSameRteContent, isStyleChanged, pxToEm, sanitizeRteJson, skipStyleDetection, } from '@brand-page-maker/utils';
11
+ import { buildInitialMarks, emToPx, isSameRteContent, sanitizeRteJson, skipStyleDetection, } from '@brand-page-maker/utils';
9
12
  import { HYPERLINK_TYPE, } from '@brand-page';
10
13
  import { letterSpacingValueConvertor } from '@brand-page-maker/convertors';
11
14
  import { useUiContentSettingsStore } from '@shared/content-settings/store';
15
+ import { useUiStyleSettingsStore } from '@shared/style-settings/store';
12
16
  import { useHistoryStore } from '@brand-page-maker/stores/history/history-store';
13
17
  import { AllSelection } from 'prosemirror-state';
18
+ import { useUiColorPaletteStore } from '@shared/color-palette/store';
14
19
  import { useHyperlink } from './hyperlink';
15
20
  import { useBubbleMenu } from './bubbleMenu';
16
- import { hasLogoColorVar, getRTEColor, getToolbarColorFromMark, resolveInitialToolbarTextColor, } from '@brand-page-maker/utils/rich-text-editor.util';
21
+ import { hasLogoColorVar, getToolbarColorFromMark, resolveInitialToolbarTextColor, hasRunTypographyOverride, isCanonicalLinked, isRoleVarRef, mergePickedMarks, normTypographyValue, readBlockTypography, relinkRoleEqualRunsChain, relinkTypographyChain, } from '@brand-page-maker/utils/rich-text-editor.util';
22
+ import { composeTextDecoration } from '@shared/text-role-typography.util';
17
23
  import { useEventTracker, EVENTS } from '../useEventTracker';
24
+ // Outlasts the slowest debounced toolbar command (spacing, 300 ms). See undo-redo.md.
25
+ const USER_COMMAND_WINDOW_MS = 1000;
18
26
  export const useExternalRichTextEditor = () => {
19
27
  const externalEditor = new Editor({
20
28
  editable: false,
@@ -25,19 +33,76 @@ export const useExternalRichTextEditor = () => {
25
33
  };
26
34
  };
27
35
  export const useRichTextEditor = (model, props, emit, fontSettings, fontStyleDropdownRef,
28
- // One entry of `textStyleOptions`; `undefined` when the selection is "none".
36
+ // The selected role's entry of `textStyleOptions`.
29
37
  selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyleTypeOptions, markedText, isHyperlinkPopupOpen, selectedLinkTypeValue) => {
30
38
  const historyStore = useHistoryStore();
39
+ const colorPaletteStore = useUiColorPaletteStore();
40
+ // A toolbar click moves focus off the editor before its command runs (Tiptap's `.focus()` restores
41
+ // it a frame later), so `isFocused` alone would file the user's edit as a mount write-back.
42
+ let userCommandUntil = 0;
43
+ const markUserCommand = () => {
44
+ userCommandUntil = Date.now() + USER_COMMAND_WINDOW_MS;
45
+ };
46
+ // The linked role's style for the var-or-literal write rule (BP-5969): a canonical-linked
47
+ // block resolves typography from its role, so a toolbar pick equal to the role is stored as
48
+ // the role var, not a literal. Undefined for legacy/unlinked blocks (they bake literals).
49
+ // Declared above the editor so RteClipboard's getContext (below) can close over it too.
50
+ const getRoleStyle = () => isCanonicalLinked(props.styles)
51
+ ? selectedGlobalTextStyles.value?.style
52
+ : undefined;
53
+ // The first-type seed a genuinely fresh field takes, or the previous run's marks when the
54
+ // field was just cleared (KeepMarksOnEmpty's capture) — shared by `beforeinput` below and
55
+ // RteClipboard's text-only paste into an empty field, so a paste matches typing.
56
+ const getFirstInputMarks = (state) => {
57
+ const clearedMarks = keepMarksOnEmptyPluginKey.getState(state);
58
+ const pickedMarks = state.storedMarks;
59
+ if (clearedMarks && clearedMarks.length > 0) {
60
+ return mergePickedMarks(clearedMarks, pickedMarks);
61
+ }
62
+ const globalStyle = selectedGlobalTextStyles.value?.style;
63
+ // Element-first colour: see the matching comment in `beforeinput` below.
64
+ const styleSource = globalStyle
65
+ ? { ...globalStyle, color: props.styles?.color }
66
+ : props.styles;
67
+ const marks = buildInitialMarks(state, styleSource, !isCanonicalLinked(props.styles));
68
+ return mergePickedMarks(marks, pickedMarks);
69
+ };
31
70
  const editor = new Editor({
32
71
  content: model.value ?? '',
33
72
  editable: !props.readOnly,
34
- extensions: getRteExtensions({
35
- restrictStarterKit: true,
36
- editing: {
37
- placeholder: props.placeholder,
38
- maxLength: props.maxLength,
39
- },
40
- }),
73
+ extensions: [
74
+ ...getRteExtensions({
75
+ restrictStarterKit: true,
76
+ editing: {
77
+ placeholder: props.placeholder,
78
+ maxLength: props.maxLength,
79
+ },
80
+ }),
81
+ // Captures a cleared run's marks so the first-type seed below can restore the
82
+ // style on retype (rather than reseeding from the role).
83
+ KeepMarksOnEmpty,
84
+ RoleTypographyFill.configure({
85
+ getFillSource: () => {
86
+ const role = isCanonicalLinked(props.styles)
87
+ ? selectedGlobalTextStyles.value?.style
88
+ : undefined;
89
+ return role
90
+ ? {
91
+ role: role,
92
+ block: props.styles,
93
+ }
94
+ : undefined;
95
+ },
96
+ }),
97
+ RteClipboard.configure({
98
+ getContext: () => ({
99
+ role: getRoleStyle(),
100
+ block: props.styles,
101
+ colors: colorPaletteStore.colors,
102
+ }),
103
+ getFirstInputMarks,
104
+ }),
105
+ ],
41
106
  editorProps: {
42
107
  handleDOMEvents: {
43
108
  drop(view, event) {
@@ -46,86 +111,19 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
46
111
  },
47
112
  beforeinput(view, event) {
48
113
  const { state } = view;
49
- // On first insert into an empty doc, set storedMarks to global styles so all typed chars inherit them
50
- if (event.inputType === 'insertText' &&
51
- state.doc.textContent === '') {
52
- const globalStyle = selectedGlobalTextStyles.value?.style;
53
- // Element-first colour: once the doc is emptied, freshly-typed text must
54
- // inherit a linked element's colour override (a creation-time contrast bake,
55
- // or a colour picked while linked), not the linked global colour. Typography
56
- // still comes from the global style (the element is linked), mirroring
57
- // resolveTextColor's colour-only cascade.
58
- const styleSource = globalStyle
59
- ? {
60
- ...globalStyle,
61
- color: props.styles?.color || globalStyle.color,
62
- }
63
- : props.styles;
64
- const marks = buildInitialMarks(state, styleSource);
65
- const chain = editor.chain();
66
- if (props.styles.textAlign)
67
- chain.setTextAlign(props.styles.textAlign);
68
- skipStyleDetection(chain, marks).run();
114
+ if (event.inputType !== 'insertText' ||
115
+ state.doc.textContent !== '') {
116
+ return false;
69
117
  }
118
+ const chain = editor.chain();
119
+ // textAlign is a block-node attr, not a mark, and a full clear resets it — so
120
+ // re-apply the element's alignment regardless of which seed `getFirstInputMarks`
121
+ // takes below (it's the one thing that survives a full clear).
122
+ if (props.styles.textAlign)
123
+ chain.setTextAlign(props.styles.textAlign);
124
+ skipStyleDetection(chain, getFirstInputMarks(state)).run();
70
125
  return false;
71
126
  },
72
- copy(view, event) {
73
- const selection = view.state.selection;
74
- if (selection.empty)
75
- return;
76
- const data = event.clipboardData;
77
- const styleData = JSON.stringify(props.styles);
78
- const slice = selection.content(), { dom, text } = view.serializeForClipboard(slice);
79
- if (data) {
80
- event.preventDefault();
81
- data.clearData();
82
- data.setData('text/html', dom.innerHTML);
83
- data.setData('text/plain', text);
84
- if (styleData)
85
- data.setData('application/x-rte-styles', styleData);
86
- }
87
- return true;
88
- },
89
- paste(view, event) {
90
- // Unified paste handler: strip styles if no styleData, enforce maxLength, handle selection
91
- const styleData = event.clipboardData?.getData('application/x-rte-styles');
92
- const pastedText = event.clipboardData?.getData('text/plain') || '';
93
- const { state, dispatch } = view;
94
- const { from, to } = state.selection;
95
- let tr = state.tr;
96
- if (styleData) {
97
- try {
98
- const pastedStyles = JSON.parse(styleData);
99
- const fontStyleChanges = {
100
- color: pastedStyles.color,
101
- fontFamily: pastedStyles.fontFamily,
102
- fontSize: pastedStyles.fontSize,
103
- fontWeight: pastedStyles.fontWeight,
104
- fontStyle: pastedStyles.fontStyle,
105
- textDecoration: pastedStyles.textDecoration,
106
- lineHeight: pastedStyles.lineHeight,
107
- letterSpacing: pastedStyles.letterSpacing,
108
- textAlign: pastedStyles.textAlign,
109
- backgroundColor: pastedStyles.backgroundColor,
110
- textStyleType: undefined,
111
- };
112
- syncContentSettings(fontStyleChanges);
113
- return false;
114
- }
115
- catch {
116
- // ignore malformed styleData
117
- }
118
- }
119
- else {
120
- event.preventDefault();
121
- tr.delete(from, to);
122
- const createdMarks = buildInitialMarks(state, props.styles);
123
- tr = tr.setStoredMarks(createdMarks).insertText(pastedText, from);
124
- onSelectTextStyleType({ label: 'None' });
125
- }
126
- dispatch(tr);
127
- return true;
128
- },
129
127
  click(view, event) {
130
128
  if (isHyperlinkPopupOpen?.value)
131
129
  return false;
@@ -145,11 +143,26 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
145
143
  },
146
144
  });
147
145
  const contentSettingStore = useUiContentSettingsStore();
146
+ const styleSettingsStore = useUiStyleSettingsStore();
148
147
  const eventTracker = useEventTracker();
149
- const { toggleBold, toggleItalic, toggleUnderline, toggleStrike, toggleTextColor, toggleBackgroundColor, toggleBoldAll, toggleItalicAll, toggleUnderlineAll, toggleStrikeAll, toggleTextColorAll, unsetAllMarks, } = createFormattingActions(editor);
148
+ const { toggleBold, toggleItalic, toggleUnderline, toggleStrike, toggleTextColor, toggleBackgroundColor, boldActive, italicActive, underlineActive, strikeActive, } = createFormattingActions(editor, getRoleStyle, () => props.styles);
150
149
  const { currentAlignment, toggleTextAlign, idx: currentAlignmentIndex, keys: alignmentKeys, } = useTextAlign(editor);
151
- const { selectedFont, toggleFont, toggleFontSize, toggleFontAll, toggleFontSizeAll, } = useFont(editor, fontSettings, fontStyleDropdownRef);
152
- const { letterSpacingValue, lineHeightValue, letterSpacing, lineHeight, setLetterSpaceAll, setLineHeightAll, } = useSpacing(editor);
150
+ const { selectedFont, toggleFont, toggleFontSize } = useFont(editor, fontSettings, fontStyleDropdownRef, getRoleStyle);
151
+ const { letterSpacingValue: letterSpacingSlider, lineHeightValue: lineHeightSlider, letterSpacing, lineHeight, setLetterSpaceAll, setLineHeightAll, } = useSpacing(editor, getRoleStyle);
152
+ const letterSpacingValue = computed({
153
+ get: () => letterSpacingSlider.value,
154
+ set: (value) => {
155
+ markUserCommand();
156
+ letterSpacingSlider.value = value;
157
+ },
158
+ });
159
+ const lineHeightValue = computed({
160
+ get: () => lineHeightSlider.value,
161
+ set: (value) => {
162
+ markUserCommand();
163
+ lineHeightSlider.value = value;
164
+ },
165
+ });
153
166
  const { hyperlinkValue, setHyperlinkUrl, setHyperlinkUrlValue, removeHyperlink: removeHyperlinkFromComposable, applyHyperlinkToEditor, } = useHyperlink(editor);
154
167
  const { shouldShow, bubbleMenuOptions } = useBubbleMenu(editor, isHyperlinkPopupOpen);
155
168
  watch(() => props.styles.textAlign, (newAlignment) => {
@@ -190,44 +203,95 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
190
203
  });
191
204
  }
192
205
  });
193
- editor.on('transaction', ({ transaction }) => {
194
- // Style detection only makes sense for user styling — an unfocused
195
- // editor's transactions are mount rehydration / programmatic setContent
196
- // churn, and clearing textStyleType from those would push a phantom
197
- // style write into the model (BP-5810 family).
198
- if (!editor.isFocused) {
206
+ // BP-5969 (ADR-0019): the auto-detach that cleared `textStyleType` whenever the doc's
207
+ // style changed is gone — a style edit is now a per-run mark and the block keeps its
208
+ // role. (Was: `editor.on('transaction')` → `onSelectTextStyleType('None')`.)
209
+ // Refresh the B/I/U/S button state from the effective formatting (textStyle attr, resolved
210
+ // against the role, OR a legacy semantic mark). It runs on every transaction: a format picked with
211
+ // nothing selected only sets a stored mark, which fires neither `update` nor `selectionUpdate`.
212
+ const syncFormattingActiveState = () => {
213
+ fontSettings.isBold = boldActive();
214
+ fontSettings.isItalic = italicActive();
215
+ fontSettings.isUnderline = underlineActive();
216
+ fontSettings.isStrike = strikeActive();
217
+ };
218
+ // Skipped while a history snapshot applies, as `selectionUpdate` is (BP-5506).
219
+ editor.on('transaction', () => {
220
+ if (historyStore.isApplyingSnapshot)
199
221
  return;
200
- }
201
- if (isStyleChanged(transaction) && props.styles.textStyleType) {
202
- onSelectTextStyleType({
203
- label: 'None',
204
- });
205
- }
222
+ syncFormattingActiveState();
206
223
  });
224
+ // A role edit (Style tab, AI) reaches the editor without a transaction. An empty one repaints
225
+ // the B/I/U/S state and the box's role fill (`RoleTypographyFill`) without touching the doc.
226
+ watch(() => selectedGlobalTextStyles.value?.style, () => {
227
+ if (editor.isDestroyed)
228
+ return;
229
+ editor.view.dispatch(editor.state.tr.setMeta('addToHistory', false));
230
+ }, { deep: true });
207
231
  // Update model when editor content changes. RTE content is stored as Tiptap
208
232
  // JSON (BP-5787). getJSON() is already in hand (the editor holds the doc) and
209
233
  // is sanitised natively — no getHTML(), no DOMPurify, no extra editor — so
210
234
  // the per-keystroke path allocates nothing heavy.
211
235
  editor.on('update', () => {
212
- // An update fired while the editor is unfocused is TipTap rewriting the
213
- // model back into its canonical form during mount rehydration or a
214
- // programmatic setContent — not a user edit. Tag the emit so the write
215
- // folds into the current undo head instead of pushing a phantom entry
216
- // (BP-5810). The flag travels WITH the value through the debounced
217
- // field → store chain and arms the history merge at the moment of the
218
- // store write — arming here at emit time would lapse before the
219
- // debounce fires. Genuine edits happen while focused and commit
220
- // normally.
221
- //
222
- // Known limitation: a programmatic toolbar command run on an editor the
223
- // user hasn't focused yet would also merge (losing that undo step). Today
224
- // the RTE only mounts inside an already-open settings drawer and the user
225
- // focuses it before formatting, so this doesn't occur — revisit if a
226
- // consumer ever drives toolbar actions on an unfocused editor.
236
+ // An update fired while the editor is unfocused and no toolbar command is in flight is
237
+ // TipTap rewriting the model into its canonical form during mount rehydration or a
238
+ // programmatic setContent — not a user edit. Tag the emit so the write folds into the
239
+ // current undo head instead of pushing a phantom entry (BP-5810). The flag travels WITH
240
+ // the value through the debounced field → store chain and arms the history merge at the
241
+ // moment of the store write — arming here at emit time would lapse before the debounce
242
+ // fires. Typing (focused) and toolbar commands (`markUserCommand`) commit normally.
227
243
  emit('update:modelValue', sanitizeRteJson(editor.getJSON()), {
228
- isHydrationWrite: !editor.isFocused,
244
+ isHydrationWrite: !editor.isFocused && Date.now() > userCommandUntil,
229
245
  });
230
246
  });
247
+ // The toolbar's read of the editor at the cursor: a mark holding a role var (or no mark) shows the
248
+ // linked role's value, a literal shows itself. Colours fall back to the given values when the run
249
+ // has none, so the mount-time seed can pass the element colour it resolved.
250
+ const syncToolbarFromEditor = ({ textColorFallback = '#000000', backgroundColorFallback = 'transparent', } = {}) => {
251
+ const textStyleAttributes = editor.getAttributes('textStyle');
252
+ const highlightAttributes = editor.getAttributes('highlight');
253
+ const focusedAlignment = editor.getAttributes(editor.state.selection.$anchor.node().type.name);
254
+ const roleStyle = getRoleStyle();
255
+ const markFontFamily = textStyleAttributes?.fontFamily;
256
+ const displayFont = markFontFamily && !isRoleVarRef(markFontFamily)
257
+ ? markFontFamily.replace(/^['"]|['"]$/g, '')
258
+ : (roleStyle?.fontFamily ?? 'Lato');
259
+ selectedFont.value = displayFont;
260
+ fontSettings.selectedFont = displayFont;
261
+ const markFontSize = textStyleAttributes?.fontSize;
262
+ const sizeSource = markFontSize && !isRoleVarRef(markFontSize)
263
+ ? markFontSize
264
+ : (roleStyle?.fontSize ?? fontSettings.selectedFontSize);
265
+ fontSettings.selectedFontSizePx = Math.ceil(parseFloat(emToPx(sizeSource)));
266
+ // A palette reference is kept verbatim (so ColorField can highlight the swatch); a literal is
267
+ // hex-normalised — Color().hex() throws on a var(), so the split lives in getToolbarColorFromMark.
268
+ fontSettings.selectedTextColor = getToolbarColorFromMark(textStyleAttributes?.color, textColorFallback);
269
+ fontSettings.selectedBackgroundColor = getToolbarColorFromMark(highlightAttributes?.color, backgroundColorFallback);
270
+ syncFormattingActiveState();
271
+ const markLineHeight = textStyleAttributes.lineHeight;
272
+ lineHeight.value =
273
+ markLineHeight && !isRoleVarRef(markLineHeight)
274
+ ? markLineHeight
275
+ : (roleStyle?.lineHeight ?? '1');
276
+ const markLetterSpacing = textStyleAttributes?.letterSpacing;
277
+ const letterSpacingSource = markLetterSpacing && !isRoleVarRef(markLetterSpacing)
278
+ ? markLetterSpacing
279
+ : roleStyle?.letterSpacing;
280
+ letterSpacing.value = letterSpacingSource
281
+ ? letterSpacingValueConvertor.convert({
282
+ letterSpacing: letterSpacingSource,
283
+ })
284
+ : '0';
285
+ if (focusedAlignment && focusedAlignment.textAlign) {
286
+ const idx = alignmentKeys.indexOf(focusedAlignment.textAlign);
287
+ if (idx !== -1) {
288
+ currentAlignmentIndex.value = idx;
289
+ }
290
+ }
291
+ else {
292
+ currentAlignmentIndex.value = 0;
293
+ }
294
+ };
231
295
  editor.on('selectionUpdate', () => {
232
296
  // Skip while a history snapshot is being applied — `setContent` fires
233
297
  // selectionUpdate before the editor has fully rehydrated, which causes
@@ -236,9 +300,6 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
236
300
  // after apply completes, which lands the correct values (BP-5506).
237
301
  if (historyStore.isApplyingSnapshot)
238
302
  return;
239
- const textStyleAttributes = editor.getAttributes('textStyle');
240
- const highlightAttributes = editor.getAttributes('highlight');
241
- const focusedAlignment = editor.getAttributes(editor.state.selection.$anchor.node().type.name);
242
303
  const selection = editor.state.selection;
243
304
  if (selection instanceof AllSelection) {
244
305
  // to prevent selecting editor state
@@ -250,54 +311,19 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
250
311
  }
251
312
  // TODO: resolve the issue of missing style on text between empty lines
252
313
  // retainStyleOnEmptyLine(editor, selection);
253
- if (textStyleAttributes && textStyleAttributes.fontFamily) {
254
- const font = textStyleAttributes.fontFamily.replace(/^['"]|['"]$/g, '');
255
- selectedFont.value = font;
256
- fontSettings.selectedFont = font;
257
- }
258
- else {
259
- selectedFont.value = 'Lato';
260
- fontSettings.selectedFont = 'Lato';
261
- }
262
- if (textStyleAttributes && textStyleAttributes.fontSize) {
263
- fontSettings.selectedFontSizePx = Math.ceil(parseFloat(emToPx(textStyleAttributes.fontSize)));
264
- }
265
- else {
266
- fontSettings.selectedFontSizePx = Math.ceil(parseFloat(emToPx(fontSettings.selectedFontSize)));
267
- }
268
- // Reflect the active mark colour on the toolbar. A palette reference is kept
269
- // verbatim (so ColorField can highlight the swatch); a literal is hex-normalised —
270
- // Color().hex() throws on a var(), so the split lives in getToolbarColorFromMark.
271
- fontSettings.selectedTextColor = getToolbarColorFromMark(textStyleAttributes?.color, '#000000');
272
- fontSettings.selectedBackgroundColor = getToolbarColorFromMark(highlightAttributes?.color, 'transparent');
273
- if (textStyleAttributes.lineHeight) {
274
- lineHeight.value = textStyleAttributes.lineHeight;
275
- }
276
- else {
277
- lineHeight.value = '1';
278
- }
279
- if (textStyleAttributes && textStyleAttributes.letterSpacing) {
280
- letterSpacing.value = letterSpacingValueConvertor.convert({
281
- letterSpacing: textStyleAttributes.letterSpacing,
282
- });
283
- }
284
- else {
285
- letterSpacing.value = '0';
286
- }
287
- if (focusedAlignment && focusedAlignment.textAlign) {
288
- const idx = alignmentKeys.indexOf(focusedAlignment.textAlign);
289
- if (idx !== -1) {
290
- currentAlignmentIndex.value = idx;
291
- }
292
- }
293
- else {
294
- currentAlignmentIndex.value = 0;
295
- }
314
+ syncToolbarFromEditor();
296
315
  });
297
316
  const setInitialStyleSettings = (selectedTextStyle) => {
298
317
  const globalStyles = selectedTextStyle ?? selectedGlobalTextStyles.value?.style;
299
318
  const currentAlignment = editor.getAttributes(editor.state.selection.$anchor.node().type.name);
300
319
  if (globalStyles) {
320
+ // A canonical-linked block inherits typography from the role CSS class and stores
321
+ // only its per-property OVERRIDES (BP-5969). Re-deriving the role's typography onto
322
+ // the element on every RTE mount clobbered those overrides — selecting a block
323
+ // reverted its title to the role font/size — so bake typography here only for
324
+ // legacy/unlinked blocks (which still carry the resolved style inline). Mirrors the
325
+ // isCanonicalLinked gate in buildInitialMarks / getUpdatedHTMLFromEditor.
326
+ const bakeTypography = !isCanonicalLinked(props.styles);
301
327
  // sync content settings style — a mount-time re-derivation, not a user
302
328
  // edit. Flag it so the store folds it into the current undo head: this
303
329
  // write lands ~100ms BEFORE the editor's canonical text write-back, and
@@ -307,32 +333,39 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
307
333
  id: props.rawId,
308
334
  name: props.name,
309
335
  value: {
310
- fontSize: globalStyles.fontSize,
311
- fontFamily: globalStyles.fontFamily,
312
- fontWeight: globalStyles.fontWeight,
313
- fontStyle: globalStyles.fontStyle,
314
- textDecoration: globalStyles.textDecoration,
315
- // Keep an element colour override (a creation-time contrast bake, or a
316
- // colour picked while linked) — only fall back to the global style's colour
317
- // when the element has none, mirroring `resolveTextColor`'s element-first
318
- // cascade. Blindly taking `globalStyles.color` here re-derived the linked
319
- // colour on every RTE mount and clobbered the override.
320
- color: props.styles?.color || globalStyles.color,
321
- lineHeight: globalStyles.lineHeight,
322
- letterSpacing: globalStyles.letterSpacing,
336
+ ...(bakeTypography
337
+ ? {
338
+ fontSize: globalStyles.fontSize,
339
+ fontFamily: globalStyles.fontFamily,
340
+ fontWeight: globalStyles.fontWeight,
341
+ fontStyle: globalStyles.fontStyle,
342
+ textDecoration: globalStyles.textDecoration,
343
+ lineHeight: globalStyles.lineHeight,
344
+ letterSpacing: globalStyles.letterSpacing,
345
+ }
346
+ : {}),
347
+ // The element's own colour override (a creation-time contrast bake, or a colour
348
+ // picked while linked). ADR-0020: the role carries no colour, so there is no
349
+ // global fallback — an uncoloured element renders the page base coat.
350
+ color: props.styles?.color,
323
351
  },
324
352
  isHydrationWrite: !editor.isFocused,
325
353
  });
326
- // sync toolbar editor styles
327
- fontSettings.selectedFont = globalStyles?.fontFamily ?? 'Lato';
328
- fontSettings.selectedFontSize = globalStyles?.fontSize ?? '2.25em';
329
- fontSettings.selectedFontSizePx = Math.ceil(parseFloat(emToPx(globalStyles?.fontSize ?? '2.25em')));
354
+ // sync toolbar editor styles — show the block's EFFECTIVE typography (its override,
355
+ // else the linked role) so the toolbar matches the render, not the role blindly.
356
+ const effectiveFontSize = props.styles?.fontSize ?? globalStyles?.fontSize ?? '2.25em';
357
+ fontSettings.selectedFont =
358
+ props.styles?.fontFamily ?? globalStyles?.fontFamily ?? 'Lato';
359
+ fontSettings.selectedFontSize = effectiveFontSize;
360
+ fontSettings.selectedFontSizePx = Math.ceil(parseFloat(emToPx(effectiveFontSize)));
330
361
  // For an RTE field the mark is the source of truth — the render and the focus-time
331
362
  // `selectionUpdate` both paint from it — so seed the swatch from the mark's first
332
363
  // coloured run, falling back to the element→global cascade. Otherwise the unfocused
333
364
  // swatch shows the linked global while the text renders its baked frame/override
334
365
  // colour, and only snaps to the right colour on focus (BP-5886).
335
- fontSettings.selectedTextColor = resolveInitialToolbarTextColor(model.value, props.styles?.color, globalStyles.color);
366
+ // BP-5969 (ADR-0020): the role contributes no colour — seed the swatch from the RTE
367
+ // mark, else the element's own colour.
368
+ fontSettings.selectedTextColor = resolveInitialToolbarTextColor(model.value, props.styles?.color);
336
369
  // A global text style has no backgroundColor, so this resolves to undefined there.
337
370
  const backgroundColour = 'backgroundColor' in globalStyles
338
371
  ? globalStyles.backgroundColor
@@ -348,142 +381,78 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
348
381
  currentAlignment?.textAlign !== props.styles.textAlign) {
349
382
  toggleTextAlign(props.styles.textAlign);
350
383
  }
351
- }
352
- else if (props.styles) {
353
- // copy the content settings styles to the editor
354
- fontSettings.selectedFont = props.styles?.fontFamily ?? 'Lato';
355
- fontSettings.selectedFontSize = props.styles?.fontSize ?? '2.25em';
356
- fontSettings.selectedFontSizePx = Math.ceil(parseFloat(emToPx(props.styles?.fontSize ?? '2.25em')));
357
- // No linked global (props.styles carries no textStyleType) — still resolve the RTE
358
- // mark first, so a field whose colour lives only in its mark (e.g. the tipping/payment
359
- // success message, which has no style object) shows it instead of collapsing to black.
360
- fontSettings.selectedTextColor = resolveInitialToolbarTextColor(model.value, props.styles?.color);
361
- fontSettings.selectedBackgroundColor = hasLogoColorVar(props.styles?.backgroundColor ?? '')
362
- ? 'transparent'
363
- : (props.styles?.backgroundColor ?? 'transparent');
364
- lineHeight.value = props.styles?.lineHeight?.includes('em')
365
- ? emToPx(props.styles?.lineHeight ?? '1em')
366
- : (props.styles?.lineHeight ?? '1');
367
- letterSpacing.value = letterSpacingValueConvertor.convert(props.styles ?? {});
368
- if (props.styles?.textAlign &&
369
- currentAlignment?.textAlign !== props.styles.textAlign) {
370
- toggleTextAlign(props.styles.textAlign);
371
- }
372
- }
373
- };
374
- const copyGlobalStyleSettings = (selectedTextStyle) => {
375
- const globalStyles = selectedTextStyle ?? selectedGlobalTextStyles.value?.style;
376
- if (globalStyles) {
377
- globalStyles.fontWeight === 'bold' && toggleBoldAll();
378
- globalStyles.fontStyle && toggleItalicAll();
379
- globalStyles.textDecoration?.includes('underline') &&
380
- toggleUnderlineAll();
381
- globalStyles.textDecoration?.includes('line-through') &&
382
- toggleStrikeAll();
383
- if (globalStyles.color) {
384
- if (!hasLogoColorVar(globalStyles.color)) {
385
- toggleTextColorAll(globalStyles.color);
386
- fontSettings.selectedTextColor = globalStyles.color;
387
- }
388
- else {
389
- // Apply logo color using CSS variable
390
- toggleTextColorAll(getRTEColor(globalStyles.color, 'text'));
391
- fontSettings.selectedTextColor = '#000000';
392
- }
393
- }
394
- globalStyles.fontFamily && toggleFontAll(globalStyles.fontFamily);
395
- globalStyles.fontSize && toggleFontSizeAll(globalStyles.fontSize);
396
- globalStyles.lineHeight && setLineHeightAll(globalStyles.lineHeight);
397
- globalStyles.letterSpacing &&
398
- setLetterSpaceAll(globalStyles.letterSpacing);
399
- props.styles.textAlign &&
400
- toggleTextAlign(props.styles.textAlign ?? 'none');
384
+ // Show the runs' own values (the role, or a per-run override) before the first click.
385
+ syncToolbarFromEditor({
386
+ textColorFallback: fontSettings.selectedTextColor,
387
+ backgroundColorFallback: fontSettings.selectedBackgroundColor,
388
+ });
401
389
  }
402
390
  };
391
+ // BP-5969 (ADR-0019): a toolbar edit applies a TipTap mark ONLY. The old sync wrote
392
+ // the flattened style back onto the block object AND cleared its role link
393
+ // (`textStyleType: undefined`) — that dual source of truth is the "a per-run colour
394
+ // edit repaints the whole block / drops the role" bug class. Now per-run formatting
395
+ // lives on marks; the block stays linked; whole-box size/family are authored from the
396
+ // sidebar. Alignment is the one block-level toolbar action, so it still persists — but
397
+ // without detaching the role.
403
398
  const triggerEditorStyleChange = (editorOption) => {
404
- const fontStyleChanges = { ...props.styles, textStyleType: undefined };
399
+ markUserCommand();
405
400
  switch (editorOption.type) {
406
401
  case 'fontFamily':
407
402
  toggleFont(editorOption.value);
408
- fontStyleChanges.fontFamily = editorOption.value;
409
403
  break;
410
- case 'fontSize':
404
+ case 'fontSize': {
411
405
  const size = editorOption.value;
412
406
  fontSettings.selectedFontSizePx = size.includes('em')
413
407
  ? Math.ceil(parseFloat(emToPx(size)))
414
408
  : parseInt(size);
415
409
  toggleFontSize(size);
416
- fontStyleChanges.fontSize = size.includes('em') ? size : pxToEm(size);
417
410
  break;
411
+ }
418
412
  case 'fontWeight':
419
413
  toggleBold();
420
- editor.isActive('bold')
421
- ? (fontStyleChanges.fontWeight = 'bold')
422
- : (fontStyleChanges.fontWeight = undefined);
423
414
  break;
424
415
  case 'fontStyle':
425
416
  toggleItalic();
426
- editor.isActive('italic')
427
- ? (fontStyleChanges.fontStyle = 'italic')
428
- : (fontStyleChanges.fontStyle = undefined);
429
417
  break;
430
418
  case 'textDecorationLine':
431
419
  toggleUnderline();
432
- editor.isActive('underline')
433
- ? fontStyleChanges.textDecoration
434
- ? (fontStyleChanges.textDecoration =
435
- fontStyleChanges.textDecoration + ' underline')
436
- : (fontStyleChanges.textDecoration = 'underline')
437
- : (fontStyleChanges.textDecoration =
438
- fontStyleChanges.textDecoration?.replace('underline', ''));
439
420
  break;
440
421
  case 'textDecorationStrike':
441
422
  toggleStrike();
442
- editor.isActive('strike')
443
- ? fontStyleChanges.textDecoration
444
- ? (fontStyleChanges.textDecoration =
445
- fontStyleChanges.textDecoration + ' line-through')
446
- : (fontStyleChanges.textDecoration = 'line-through')
447
- : (fontStyleChanges.textDecoration =
448
- fontStyleChanges.textDecoration?.replace('line-through', ''));
449
423
  break;
450
424
  case 'textColor':
451
425
  toggleTextColor(editorOption.value);
452
- fontStyleChanges.color = editorOption.value;
453
426
  break;
454
427
  case 'backgroundColor':
455
428
  toggleBackgroundColor(editorOption.value);
456
- fontStyleChanges.backgroundColor = editorOption.value;
457
429
  break;
458
430
  case 'lineHeight':
459
431
  setLineHeightAll(editorOption.value);
460
- fontStyleChanges.lineHeight = editorOption.value;
461
432
  break;
462
433
  case 'letterSpacing':
463
434
  setLetterSpaceAll(editorOption.value);
464
- fontStyleChanges.letterSpacing = letterSpacingValueConvertor.convert({
465
- letterSpacing: editorOption.value,
466
- });
467
435
  break;
468
436
  case 'textAlign':
469
437
  toggleTextAlign();
470
- fontStyleChanges.textAlign = currentAlignment.value.alignment;
438
+ persistBlockTextAlign(currentAlignment.value.alignment);
471
439
  break;
472
440
  case 'hyperlink':
473
441
  setHyperlinkUrl(editorOption.value);
474
442
  break;
475
443
  }
476
- syncContentSettings(fontStyleChanges);
477
444
  };
478
- const syncContentSettings = (fontStyleChanges) => {
445
+ // Alignment is block-level (not a per-run mark, not a role property), so it persists to
446
+ // the block/item style — writing ONLY `textAlign`, so the role link is untouched.
447
+ const persistBlockTextAlign = (textAlign) => {
448
+ if (!textAlign)
449
+ return;
450
+ const value = { textAlign };
479
451
  if (props.name === 'textItems') {
480
452
  contentSettingStore.updateTextItemTextStyleTypeWithStyles({
481
453
  id: props.rawId,
482
454
  name: props.name,
483
- value: {
484
- ...fontStyleChanges,
485
- fontSize: fontSettings.selectedFontSize,
486
- },
455
+ value,
487
456
  index: props.textItemIndex,
488
457
  });
489
458
  }
@@ -491,12 +460,83 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
491
460
  contentSettingStore.updateTextStyles({
492
461
  id: props.rawId,
493
462
  name: props.name,
494
- value: {
495
- ...fontStyleChanges,
496
- },
463
+ value,
497
464
  });
498
465
  }
499
466
  };
467
+ // The subset of the block's typography that DIFFERS from its linked role — the promotable
468
+ // override set. Empty when the block matches its role (colour is element-first, excluded).
469
+ const getTypographyOverride = () => {
470
+ const role = selectedGlobalTextStyles.value?.style;
471
+ if (!role)
472
+ return {};
473
+ const override = {};
474
+ Object.entries(readBlockTypography(editor)).forEach(([key, value]) => {
475
+ // A role-var mark is linked, not an override — the value IS the role.
476
+ if (isRoleVarRef(value))
477
+ return;
478
+ const promoted = key === 'textDecoration'
479
+ ? composeTextDecoration(role[key], value)
480
+ : value;
481
+ if (typeof promoted === 'string' &&
482
+ normTypographyValue(key, promoted) !==
483
+ normTypographyValue(key, role[key])) {
484
+ override[key] = promoted;
485
+ }
486
+ });
487
+ return override;
488
+ };
489
+ // Drives the role dropdown's `*` and the "modified style" toggle: true when any run of this
490
+ // linked block differs from its role's typography — one bold word counts.
491
+ const hasTypographyOverride = () => {
492
+ const role = getRoleStyle();
493
+ return !!role && hasRunTypographyOverride(editor, role);
494
+ };
495
+ // A word-level override has no single value to promote, so "Apply changes to all" needs a
496
+ // whole-block one.
497
+ const canApplyTypographyToRole = () => isCanonicalLinked(props.styles) &&
498
+ Object.keys(getTypographyOverride()).length > 0;
499
+ // Reset to default: re-link this block's typography to its role (see `relinkTypographyChain`).
500
+ // skipStyleDetection keeps the role link so this doesn't read as a detaching style edit.
501
+ const resetTypographyToRole = () => {
502
+ const role = getRoleStyle();
503
+ markUserCommand();
504
+ skipStyleDetection(relinkTypographyChain(editor, role)).run();
505
+ };
506
+ // A role switch resets only typography (ADR-0020): runs relink to the new role, colour stays.
507
+ // An undo/redo restores the doc that went with the role, so it only moves the dropdown tick —
508
+ // the apply bumps `snapshotAppliedToken` in the same tick as it writes the role.
509
+ watch([() => props.styles.textStyleType, () => historyStore.snapshotAppliedToken], ([newType, token], [oldType, oldToken]) => {
510
+ if (!newType || newType === oldType)
511
+ return;
512
+ textStyleTypeOptions.forEach((item) => {
513
+ item.isSelected = item.value === newType;
514
+ });
515
+ if (token === oldToken)
516
+ resetTypographyToRole();
517
+ });
518
+ // Apply to all: promote this block's whole-block typography into the role definition (every
519
+ // block linked to the role adopts it), relink this block's runs that now equal the role —
520
+ // word-level overrides stay, unlike Reset — and re-normalize siblings against the new role.
521
+ // Mirrors the sidebar TextStyleField.saveToGlobal, sourcing the overrides from the RTE marks.
522
+ const applyTypographyToRole = () => {
523
+ const type = props.styles.textStyleType;
524
+ const role = selectedGlobalTextStyles.value?.style;
525
+ const override = getTypographyOverride();
526
+ if (!type || !role || !Object.keys(override).length)
527
+ return;
528
+ const previousRole = { ...role };
529
+ const nextRole = { ...role, ...override };
530
+ markUserCommand();
531
+ styleSettingsStore.setTextStyleOption({ type, style: nextRole });
532
+ skipStyleDetection(relinkRoleEqualRunsChain(editor, nextRole, previousRole)).run();
533
+ contentSettingStore.renormalizeTextStylesForRole(type, previousRole, {
534
+ id: props.rawId,
535
+ name: props.name,
536
+ index: props.textItemIndex,
537
+ doc: sanitizeRteJson(editor.getJSON()),
538
+ });
539
+ };
500
540
  const onFocus = () => {
501
541
  emit('focus');
502
542
  };
@@ -561,6 +601,7 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
561
601
  const selectionRange = selection
562
602
  ? { from: selection.from, to: selection.to }
563
603
  : undefined;
604
+ markUserCommand();
564
605
  applyHyperlinkToEditor(url, text, selectionRange);
565
606
  isHyperlinkPopupOpen.value = false;
566
607
  break;
@@ -572,6 +613,7 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
572
613
  content_type: props.contentType,
573
614
  },
574
615
  });
616
+ markUserCommand();
575
617
  removeHyperlinkFromComposable();
576
618
  isHyperlinkPopupOpen.value = false;
577
619
  break;
@@ -599,8 +641,10 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
599
641
  lineHeightValue,
600
642
  selectedFont: computed(() => selectedFont.value),
601
643
  setInitialStyleSettings,
602
- copyGlobalStyleSettings,
603
- unsetAllMarks,
644
+ hasTypographyOverride,
645
+ canApplyTypographyToRole,
646
+ resetTypographyToRole,
647
+ applyTypographyToRole,
604
648
  handleHyperlink,
605
649
  hyperlinkValue,
606
650
  setHyperlinkUrlValue,