@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.
- package/lib/src/{CreatedOnBrandCrowd-de-de-DDcraD5S.js → CreatedOnBrandCrowd-de-de-BtVKllNQ.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-DtOeaisf.js → CreatedOnBrandCrowd-en-us-CX5V0v8u.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-BZpmJPew.js → CreatedOnBrandCrowd-es-es-CbA02PCL.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-CqRwC4e7.js → CreatedOnBrandCrowd-fr-ca-BQAKruBF.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-CqRwC4e7.js → CreatedOnBrandCrowd-fr-fr-BQAKruBF.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-DId9Dfjh.js → CreatedOnBrandCrowd-pt-br-Yk_yzB3s.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-DId9Dfjh.js → CreatedOnBrandCrowd-pt-pt-Yk_yzB3s.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-BTDfmOcm.js → CreatedOnDcom-de-de-DJZQbPSD.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-CeAu9Ayx.js → CreatedOnDcom-en-us-BJvNAa4l.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-WCv0K41H.js → CreatedOnDcom-es-es-CUwB1FRY.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-BlfevQDY.js → CreatedOnDcom-fr-ca-CK54U4oh.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-Cvt7MHPZ.js → CreatedOnDcom-fr-fr-DuUNBGrM.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-DipZuylv.js → CreatedOnDcom-pt-br-BfODpFNV.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-BCw4lcKN.js → CreatedOnDcom-pt-pt-Cf6u2GCg.js} +1 -1
- package/lib/src/brand-page/__fixtures__/production-text-style-resolver.fixture.d.ts +16 -0
- package/lib/src/brand-page/__fixtures__/production-text-style-resolver.fixture.js +35 -0
- package/lib/src/brand-page/components/contact-form/ContactForm.mixin.d.ts +3 -0
- package/lib/src/brand-page/components/contact-form/ContactForm.mixin.js +19 -13
- package/lib/src/brand-page/components/mailing-list/MailingList.mixin.d.ts +3 -1
- package/lib/src/brand-page/components/mailing-list/MailingList.mixin.js +17 -2
- package/lib/src/brand-page/components/navigation/button-carousel/ButtonCarouselNavigation.mixin.d.ts +11 -3
- package/lib/src/brand-page/components/navigation/button-carousel/ButtonCarouselNavigation.mixin.js +35 -1
- package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.d.ts +8 -2
- package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.js +27 -3
- package/lib/src/brand-page/components/page/Page.mixin.d.ts +5 -2
- package/lib/src/brand-page/components/page/Page.mixin.js +33 -27
- package/lib/src/brand-page/components/page-footer/PageFooter.mixin.d.ts +7 -2
- package/lib/src/brand-page/components/page-footer/PageFooter.mixin.js +21 -1
- package/lib/src/brand-page/components/payment/Payment.mixin.d.ts +5 -2
- package/lib/src/brand-page/components/payment/Payment.mixin.js +22 -2
- package/lib/src/brand-page/components/payment/support-me/SupportMe.mixin.d.ts +6 -2
- package/lib/src/brand-page/components/payment/support-me/SupportMe.mixin.js +32 -1
- package/lib/src/brand-page/components/social-links/SocialLinks.stories.js +0 -3
- package/lib/src/brand-page/components/testimonial-section/__fixtures__/data.js +0 -3
- package/lib/src/brand-page/components/text/Text.stories.js +0 -17
- package/lib/src/brand-page/constants/font.constants.d.ts +62 -0
- package/lib/src/brand-page/constants/font.constants.js +35 -0
- package/lib/src/brand-page/models/index.d.ts +23 -24
- package/lib/src/brand-page/models/index.js +20 -7
- package/lib/src/brand-page/models/navigation-styles.model.d.ts +1 -1
- package/lib/src/brand-page/models/navigation-styles.model.js +17 -8
- package/lib/src/brand-page/models/payment.model.d.ts +11 -6
- package/lib/src/brand-page/models/styles.model.d.ts +53 -7
- package/lib/src/brand-page/models/styles.model.js +115 -27
- package/lib/src/brand-page/utils/color-palette.util.d.ts +43 -23
- package/lib/src/brand-page/utils/color-palette.util.js +65 -27
- package/lib/src/brand-page/utils/color.util.d.ts +13 -9
- package/lib/src/brand-page/utils/color.util.js +56 -15
- package/lib/src/brand-page/utils/container-text-color.util.d.ts +46 -13
- package/lib/src/brand-page/utils/container-text-color.util.js +321 -41
- package/lib/src/brand-page/utils/index.d.ts +1 -0
- package/lib/src/brand-page/utils/index.js +1 -0
- package/lib/src/brand-page/utils/migration/migration-20.js +6 -2
- package/lib/src/brand-page/utils/migration/migration-21.js +34 -6
- package/lib/src/brand-page/utils/migration/migration-22.d.ts +99 -0
- package/lib/src/brand-page/utils/migration/migration-22.js +909 -0
- package/lib/src/brand-page/utils/migration.util.js +17 -0
- package/lib/src/brand-page/utils/model.util.d.ts +4 -0
- package/lib/src/brand-page/utils/model.util.js +4 -0
- package/lib/src/brand-page/utils/personalisation.util.js +9 -1
- package/lib/src/brand-page/utils/rte-role-lift.util.d.ts +72 -0
- package/lib/src/brand-page/utils/rte-role-lift.util.js +275 -0
- package/lib/src/brand-page/utils/style.util.d.ts +5 -1
- package/lib/src/brand-page/utils/style.util.js +34 -11
- package/lib/src/brand-page/utils/text-role-css.util.d.ts +19 -0
- package/lib/src/brand-page/utils/text-role-css.util.js +186 -0
- package/lib/src/brand-page/utils/text-role-reconnect.util.d.ts +90 -0
- package/lib/src/brand-page/utils/text-role-reconnect.util.js +434 -0
- package/lib/src/brand-page/utils/text-style.util.d.ts +53 -23
- package/lib/src/brand-page/utils/text-style.util.js +122 -22
- package/lib/src/brand-page/utils/view-model.util.d.ts +9 -1
- package/lib/src/brand-page/utils/view-model.util.js +124 -111
- package/lib/src/brand-page/view-models.d.ts +1 -0
- package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +4 -1
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +13 -2
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +4 -4
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +4 -1
- package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.js +0 -10
- package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/content-settings-items.fixture.js +0 -1
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +23 -138
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.js +0 -28
- package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +4 -1
- package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +5 -2
- package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +4 -1
- package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +4 -1
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +4 -1
- package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.d.ts +1 -0
- package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.js +1 -0
- package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +1 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/RoleTypographyFill.d.ts +16 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/RoleTypographyFill.js +61 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/RteClipboard.d.ts +11 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/RteClipboard.js +236 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/font.d.ts +2 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/font.js +25 -6
- package/lib/src/brand-page-maker/composables/rich-text-editor/formatting.d.ts +17 -4
- package/lib/src/brand-page-maker/composables/rich-text-editor/formatting.js +204 -17
- package/lib/src/brand-page-maker/composables/rich-text-editor/hyperlink.d.ts +1 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/hyperlink.js +29 -31
- package/lib/src/brand-page-maker/composables/rich-text-editor/keepMarksOnEmpty.d.ts +20 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/keepMarksOnEmpty.js +60 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/spacing.d.ts +2 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/spacing.js +22 -6
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +10 -4
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +319 -275
- package/lib/src/brand-page-maker/constants/config-settings-constant.js +1 -5
- package/lib/src/brand-page-maker/convertors/text-css-style-options.convertor.js +6 -2
- package/lib/src/brand-page-maker/convertors/text-size-value.convertor.d.ts +1 -1
- package/lib/src/brand-page-maker/convertors/text-size-value.convertor.js +3 -1
- package/lib/src/brand-page-maker/default-getters/payment-text-and-border-color.default-getter.js +7 -14
- package/lib/src/brand-page-maker/default-getters/text-color.default-getter.js +6 -13
- package/lib/src/brand-page-maker/models/content-settings.d.ts +8 -0
- package/lib/src/brand-page-maker/models/content-settings.js +112 -81
- package/lib/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store-utils.d.ts +2 -2
- package/lib/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store-utils.js +5 -2
- package/lib/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store.js +4 -3
- package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +1257 -117
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +6 -1
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +17 -9
- package/lib/src/brand-page-maker/stores/history/history-store.d.ts +59 -5
- package/lib/src/brand-page-maker/stores/history/history-store.js +22 -2
- package/lib/src/brand-page-maker/utils/apply-color-strategy.js +26 -8
- package/lib/src/brand-page-maker/utils/index.d.ts +2 -1
- package/lib/src/brand-page-maker/utils/index.js +2 -1
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +117 -15
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +435 -281
- package/lib/src/brand-page-maker/utils/rte-authoring.util.d.ts +4 -0
- package/lib/src/brand-page-maker/utils/rte-authoring.util.js +101 -0
- package/lib/src/brand-page-maker/utils/rte-clipboard.util.d.ts +126 -0
- package/lib/src/brand-page-maker/utils/rte-clipboard.util.js +307 -0
- package/lib/src/brand-page-maker/utils/rte-sanitize.util.js +13 -3
- package/lib/src/{bundled-translations-zfiA5Tsw.js → bundled-translations-yGrvPE5i.js} +17 -17
- package/lib/src/{bundled-translations.de-DE-ChsdSyAP.js → bundled-translations.de-DE-L4Znf8Hs.js} +17 -17
- package/lib/src/{bundled-translations.es-ES-DflsWQK0.js → bundled-translations.es-ES-D6iticrK.js} +15 -15
- package/lib/src/{bundled-translations.fr-CA-fpDRuZ52.js → bundled-translations.fr-CA-BgAVE-9k.js} +25 -25
- package/lib/src/{bundled-translations.fr-FR-Bub73Zt-.js → bundled-translations.fr-FR-B8GbyqxQ.js} +17 -17
- package/lib/src/{bundled-translations.pt-BR-BlnWE9TB.js → bundled-translations.pt-BR-DjPU3Db7.js} +25 -25
- package/lib/src/{bundled-translations.pt-PT-DmzXlnaS.js → bundled-translations.pt-PT-BaepaDpr.js} +23 -23
- package/lib/src/bundles/bundled-translations.de-DE.json +21 -2
- package/lib/src/bundles/bundled-translations.es-ES.json +21 -2
- package/lib/src/bundles/bundled-translations.fr-CA.json +21 -2
- package/lib/src/bundles/bundled-translations.fr-FR.json +21 -2
- package/lib/src/bundles/bundled-translations.json +21 -2
- package/lib/src/bundles/bundled-translations.pt-BR.json +21 -2
- package/lib/src/bundles/bundled-translations.pt-PT.json +21 -2
- package/lib/src/clients/ai-assistant-client.d.ts +1 -0
- package/lib/src/composables/useTranslate.d.ts +1 -1
- package/lib/src/composables/useTranslate.js +1 -1
- package/lib/src/css/library.brand-page-brandCrowd.min.css +303 -207
- package/lib/src/css/library.brand-page-brandPage.min.css +303 -207
- package/lib/src/css/library.brand-page-designCom.min.css +303 -207
- package/lib/src/css/library.brand-page-preview.min.css +303 -207
- package/lib/src/index.d.ts +2 -1
- package/lib/src/index.mjs +195 -191
- package/lib/src/{lib-1AqtEmvQ.js → lib-kGRlD3_P.js} +36855 -33893
- package/lib/src/lib.js +2 -1
- package/lib/src/metadata-builder/builders/footer-builder.js +4 -5
- package/lib/src/metadata-builder/builders/global-role-propagation.d.ts +58 -0
- package/lib/src/metadata-builder/builders/global-role-propagation.js +246 -0
- package/lib/src/metadata-builder/builders/global-styles-builder.d.ts +1 -0
- package/lib/src/metadata-builder/builders/global-styles-builder.js +116 -45
- package/lib/src/metadata-builder/builders/header-builder.js +13 -4
- package/lib/src/metadata-builder/builders/section-builders/about-section-builder.js +3 -3
- package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.js +3 -3
- package/lib/src/metadata-builder/builders/section-builders/booking-section-builder.js +3 -3
- package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.js +4 -4
- package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +3 -3
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.js +2 -2
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.js +2 -2
- package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.js +4 -4
- package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +3 -3
- package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +8 -2
- package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +2 -2
- package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +60 -29
- package/lib/src/metadata-builder/builders/section-field-maps.js +1 -0
- package/lib/src/metadata-builder/builders/section-field-utils.d.ts +48 -19
- package/lib/src/metadata-builder/builders/section-field-utils.js +128 -52
- package/lib/src/metadata-builder/builders/section-rules/global-styles.rules.d.ts +4 -2
- package/lib/src/metadata-builder/builders/section-rules/global-styles.rules.js +28 -12
- package/lib/src/metadata-builder/builders/section-rules/social-links.rules.js +5 -1
- package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +1 -1
- package/lib/src/metadata-builder/helpers/rte.helpers.js +97 -40
- package/lib/src/metadata-builder/metadata-executor.js +23 -1
- package/lib/src/metadata-builder/models.d.ts +2 -0
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +18 -19
- package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +18 -1
- package/lib/src/metadata-builder/sanitizers/rte-schema-check.js +1 -1
- package/lib/src/metadata-builder/sanitizers/sanitizer-rules.d.ts +0 -1
- package/lib/src/metadata-builder/sanitizers/sanitizer-rules.js +5 -8
- package/lib/src/metadata-builder/sanitizers/section-args-validator.d.ts +7 -16
- package/lib/src/metadata-builder/sanitizers/section-args-validator.js +95 -22
- package/lib/src/shared/color-palette/section-color-matches.js +9 -25
- package/lib/src/shared/color-strategies/color-strategies.d.ts +15 -0
- package/lib/src/shared/color-strategies/color-strategies.js +31 -0
- package/lib/src/shared/color-strategies/rte-color.d.ts +8 -0
- package/lib/src/shared/color-strategies/rte-color.js +16 -0
- package/lib/src/shared/color-strategies/rte-field-pairs.d.ts +23 -0
- package/lib/src/shared/color-strategies/rte-field-pairs.js +28 -0
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +9 -135
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +1 -27
- package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +12 -2
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +7 -0
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +75 -6
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +18 -7
- package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +6 -1
- package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.js +0 -7
- package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.js +8 -4
- package/lib/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.d.ts +1255 -26
- package/lib/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.js +203 -59
- package/lib/src/shared/content-settings/store/content-settings-store.d.ts +6 -0
- package/lib/src/shared/content-settings/store/content-settings-store.js +105 -8
- package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +5 -1
- package/lib/src/shared/navigation-style-settings/store/index.d.ts +7 -3
- package/lib/src/shared/navigation-style-settings/store/index.js +40 -15
- package/lib/src/shared/page-settings/components/delete-page-modal/DeletePageModal.mixin.d.ts +1 -1
- package/lib/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.d.ts +1 -0
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +17 -5
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +70 -13
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.js +10 -2
- package/lib/src/shared/page-settings/store/page-settings-store.d.ts +2 -1
- package/lib/src/shared/page-settings/store/page-settings-store.js +17 -0
- package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +4 -1
- package/lib/src/shared/rte-extensions/AutoLink.d.ts +17 -0
- package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/AutoLink.js +67 -51
- package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/MaxLength.js +4 -1
- package/lib/src/shared/rte-extensions/TextEffects.d.ts +28 -0
- package/lib/src/shared/rte-extensions/TextEffects.js +96 -0
- package/lib/src/shared/rte-extensions/ViewDomParser.d.ts +2 -0
- package/lib/src/shared/rte-extensions/ViewDomParser.js +21 -0
- package/lib/src/shared/rte-extensions.util.d.ts +25 -0
- package/lib/src/{brand-page-maker/composables/rich-text-editor/getRteExtensions.js → shared/rte-extensions.util.js} +62 -7
- package/lib/src/shared/rte-link.util.d.ts +1 -0
- package/lib/src/shared/rte-link.util.js +1 -0
- package/lib/src/shared/rte-render.util.d.ts +112 -0
- package/lib/src/shared/rte-render.util.js +255 -0
- package/lib/src/shared/rte-shape.util.d.ts +6 -0
- package/lib/src/shared/rte-shape.util.js +18 -0
- package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +2 -1
- package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +1 -0
- package/lib/src/shared/side-bar/store/side-bar-store.d.ts +2 -0
- package/lib/src/shared/side-bar/store/side-bar-store.js +9 -0
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +155 -15
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.js +7 -1
- package/lib/src/shared/style-settings/store/style-settings-store.d.ts +1 -9
- package/lib/src/shared/style-settings/store/style-settings-store.js +3 -33
- package/lib/src/shared/style-settings/text-style-size-order.d.ts +2 -0
- package/lib/src/shared/style-settings/text-style-size-order.js +13 -0
- package/lib/src/shared/text-role-typography.util.d.ts +64 -0
- package/lib/src/shared/text-role-typography.util.js +183 -0
- package/lib/src/utils/minify-brand-page-metadata.d.ts +16 -1
- package/lib/src/utils/minify-brand-page-metadata.js +31 -9
- package/package.json +1 -1
- package/src/brand-page/__fixtures__/migration-22-v21/edited-brandsite-sections.v21.json +982 -0
- package/src/brand-page/__fixtures__/migration-22-v21/new-brandcontact-every-section.v21.json +1231 -0
- package/src/brand-page/__fixtures__/migration-22-v21/new-brandpage-every-section.v21.json +1231 -0
- package/src/brand-page/__fixtures__/migration-22-v21/new-brandsite-every-section.v21.json +1243 -0
- package/src/brand-page/__fixtures__/migration-22-v21/real-brandcontact.v21.json +755 -0
- package/src/brand-page/__fixtures__/migration-22-v21/real-brandpage-general-link.v21.json +527 -0
- package/src/brand-page/__fixtures__/migration-22-v21/real-brandpage-links.v21.json +755 -0
- package/src/brand-page/__fixtures__/migration-22-v21/real-brandpage-social-links.v21.json +514 -0
- package/src/brand-page/__fixtures__/migration-22-v21/real-brandsite-about.v21.json +459 -0
- package/src/brand-page/__fixtures__/migration-22-v21/real-brandsite-footer.v21.json +469 -0
- package/src/brand-page/__fixtures__/migration-22-v21/real-brandsite-header-banner.v21.json +481 -0
- package/src/brand-page/__fixtures__/migration-22-v21/real-brandsite-sections.v21.json +800 -0
- package/src/brand-page/__fixtures__/production-text-style-resolver.fixture.ts +52 -0
- package/src/brand-page/components/about-section/AboutSection.vue.test.ts +0 -10
- package/src/brand-page/components/contact-form/ContactForm.mixin.test.ts +127 -0
- package/src/brand-page/components/contact-form/ContactForm.mixin.ts +31 -14
- package/src/brand-page/components/contact-form/ContactForm.vue +26 -12
- package/src/brand-page/components/contact-form/ContactForm.vue.test.ts +60 -0
- package/src/brand-page/components/mailing-list/MailingList.mixin.test.ts +92 -0
- package/src/brand-page/components/mailing-list/MailingList.mixin.ts +28 -3
- package/src/brand-page/components/mailing-list/MailingList.vue +9 -4
- package/src/brand-page/components/mailing-list/MailingList.vue.test.ts +63 -0
- package/src/brand-page/components/navigation/button-carousel/ButtonCarouselNavigation.mixin.ts +51 -1
- package/src/brand-page/components/navigation/button-carousel/ButtonCarouselNavigation.test.ts +114 -0
- package/src/brand-page/components/navigation/button-carousel/ButtonCarouselNavigation.vue +8 -2
- package/src/brand-page/components/navigation/navigation-carousel/NavigationCarousel.test.ts +182 -0
- package/src/brand-page/components/navigation/navigation-carousel/NavigationCarousel.vue +59 -12
- package/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.ts +40 -3
- package/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.vue +15 -7
- package/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.vue.test.ts +133 -3
- package/src/brand-page/components/page/Page.mixin.ts +41 -34
- package/src/brand-page/components/page/Page.vue +17 -6
- package/src/brand-page/components/page/Page.vue.test.ts +91 -1
- package/src/brand-page/components/page-footer/PageFooter.mixin.ts +32 -2
- package/src/brand-page/components/page-footer/PageFooter.test.ts +79 -0
- package/src/brand-page/components/page-footer/PageFooter.vue +12 -4
- package/src/brand-page/components/payment/Payment.mixin.ts +34 -2
- package/src/brand-page/components/payment/Payment.test.ts +188 -0
- package/src/brand-page/components/payment/Payment.vue +12 -5
- package/src/brand-page/components/payment/RequestPaymentStripe.vue +1 -0
- package/src/brand-page/components/payment/support-me/SupportMe.mixin.ts +49 -2
- package/src/brand-page/components/payment/support-me/SupportMe.test.ts +100 -0
- package/src/brand-page/components/payment/support-me/SupportMe.vue +7 -1
- package/src/brand-page/components/payment/support-me/SupportMe.vue.test.ts +66 -0
- package/src/brand-page/components/save-contact/SaveContactWidget.test.ts +100 -0
- package/src/brand-page/components/save-contact/SaveContactWidget.vue +6 -3
- package/src/brand-page/components/shop/PaymentModal.vue +2 -6
- package/src/brand-page/components/shop/PaymentShippingAddress.vue +6 -0
- package/src/brand-page/components/shop/Shop.vue +15 -2
- package/src/brand-page/components/shop/Shop.vue.test.ts +74 -2
- package/src/brand-page/components/social-links/SocialLinks.stories.ts +0 -3
- package/src/brand-page/components/social-links/SocialLinks.vue.test.ts +0 -3
- package/src/brand-page/components/testimonial-section/__fixtures__/data.ts +0 -3
- package/src/brand-page/components/text/Text.stories.ts +0 -17
- package/src/brand-page/components/text-wrapper/TextWrapper.parity.test.ts +136 -0
- package/src/brand-page/components/text-wrapper/TextWrapper.test.ts +358 -0
- package/src/brand-page/components/text-wrapper/TextWrapper.vue +82 -22
- package/src/brand-page/constants/font.constants.ts +37 -0
- package/src/brand-page/models/footer-icon-color.test.ts +22 -0
- package/src/brand-page/models/index.ts +50 -28
- package/src/brand-page/models/navigation-styles.model.test.ts +77 -1
- package/src/brand-page/models/navigation-styles.model.ts +26 -9
- package/src/brand-page/models/payment.model.ts +15 -6
- package/src/brand-page/models/styles.model.test.ts +104 -0
- package/src/brand-page/models/styles.model.ts +181 -47
- package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +619 -115
- package/src/brand-page/utils/__snapshots__/migration2.util.test.ts.snap +150 -9
- package/src/brand-page/utils/__snapshots__/model.util.test.ts.snap +300 -18
- package/src/brand-page/utils/color-palette.util.test.ts +126 -1
- package/src/brand-page/utils/color-palette.util.ts +92 -26
- package/src/brand-page/utils/color.util.test.ts +62 -29
- package/src/brand-page/utils/color.util.ts +77 -14
- package/src/brand-page/utils/container-text-color.util.test.ts +672 -26
- package/src/brand-page/utils/container-text-color.util.ts +472 -46
- package/src/brand-page/utils/index.ts +1 -0
- package/src/brand-page/utils/migration/__snapshots__/migration-22-output/edited-brandsite-sections.v22.json +1191 -0
- package/src/brand-page/utils/migration/__snapshots__/migration-22-output/new-brandcontact-every-section.v22.json +2026 -0
- package/src/brand-page/utils/migration/__snapshots__/migration-22-output/new-brandpage-every-section.v22.json +2017 -0
- package/src/brand-page/utils/migration/__snapshots__/migration-22-output/new-brandsite-every-section.v22.json +2031 -0
- package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandcontact.v22.json +1145 -0
- package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandpage-general-link.v22.json +645 -0
- package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandpage-links.v22.json +1136 -0
- package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandpage-social-links.v22.json +662 -0
- package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandsite-about.v22.json +638 -0
- package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandsite-footer.v22.json +610 -0
- package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandsite-header-banner.v22.json +660 -0
- package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandsite-sections.v22.json +1132 -0
- package/src/brand-page/utils/migration/migration-01.ts +293 -237
- package/src/brand-page/utils/migration/migration-02.ts +8 -1
- package/src/brand-page/utils/migration/migration-20.ts +6 -3
- package/src/brand-page/utils/migration/migration-20_5.test.ts +5 -2
- package/src/brand-page/utils/migration/migration-21.test.ts +34 -0
- package/src/brand-page/utils/migration/migration-21.ts +46 -10
- package/src/brand-page/utils/migration/migration-22.fixed-input.test.ts +43 -0
- package/src/brand-page/utils/migration/migration-22.test.ts +4103 -0
- package/src/brand-page/utils/migration/migration-22.text-font-family.test.ts +72 -0
- package/src/brand-page/utils/migration/migration-22.ts +1336 -0
- package/src/brand-page/utils/migration.util.test.ts +146 -32
- package/src/brand-page/utils/migration.util.ts +18 -0
- package/src/brand-page/utils/model.util.ts +4 -0
- package/src/brand-page/utils/personalisation.util.test.ts +148 -3
- package/src/brand-page/utils/personalisation.util.ts +9 -1
- package/src/brand-page/utils/rte-role-lift.util.ts +409 -0
- package/src/brand-page/utils/style.util.test.ts +35 -2
- package/src/brand-page/utils/style.util.ts +45 -11
- package/src/brand-page/utils/text-role-css.util.test.ts +525 -0
- package/src/brand-page/utils/text-role-css.util.ts +321 -0
- package/src/brand-page/utils/text-role-reconnect.util.test.ts +604 -0
- package/src/brand-page/utils/text-role-reconnect.util.ts +727 -0
- package/src/brand-page/utils/text-style.util.test.ts +305 -0
- package/src/brand-page/utils/text-style.util.ts +198 -24
- package/src/brand-page/utils/view-model.page-data.test.ts +232 -0
- package/src/brand-page/utils/view-model.util.test.ts +954 -133
- package/src/brand-page/utils/view-model.util.ts +187 -139
- package/src/brand-page/view-models.ts +4 -0
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.blank-site.test.ts +57 -0
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +9 -5
- package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +0 -10
- package/src/brand-page-maker/components/brand-page-maker/__fixtures__/content-settings-items.fixture.ts +0 -1
- package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.ts +0 -44
- package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +253 -200
- package/src/brand-page-maker/components/shop/AddOrEditProductContainer.vue +1 -0
- package/src/brand-page-maker/components/template-preview/TemplatePreview.vue +1 -0
- package/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.ts +2 -0
- package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +1 -0
- package/src/brand-page-maker/composables/rich-text-editor/block-typography.test.ts +519 -0
- package/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.test.ts +1 -1
- package/src/brand-page-maker/composables/rich-text-editor/extensions/MaxLength.test.ts +26 -1
- package/src/brand-page-maker/composables/rich-text-editor/extensions/RoleTypographyFill.test.ts +110 -0
- package/src/brand-page-maker/composables/rich-text-editor/extensions/RoleTypographyFill.ts +99 -0
- package/src/brand-page-maker/composables/rich-text-editor/extensions/RteClipboard.ts +397 -0
- package/src/brand-page-maker/composables/rich-text-editor/extensions/ViewDomParser.test.ts +139 -0
- package/src/brand-page-maker/composables/rich-text-editor/font.ts +36 -5
- package/src/brand-page-maker/composables/rich-text-editor/formatting.test.ts +375 -1
- package/src/brand-page-maker/composables/rich-text-editor/formatting.ts +301 -17
- package/src/brand-page-maker/composables/rich-text-editor/hyperlink.test.ts +82 -1
- package/src/brand-page-maker/composables/rich-text-editor/hyperlink.ts +28 -34
- package/src/brand-page-maker/composables/rich-text-editor/keepMarksOnEmpty.test.ts +80 -0
- package/src/brand-page-maker/composables/rich-text-editor/keepMarksOnEmpty.ts +75 -0
- package/src/brand-page-maker/composables/rich-text-editor/spacing.ts +31 -6
- package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.test.ts +2485 -0
- package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +435 -337
- package/src/brand-page-maker/constants/config-settings-constant.ts +0 -6
- package/src/brand-page-maker/convertors/text-css-style-options.convertor.test.ts +43 -0
- package/src/brand-page-maker/convertors/text-css-style-options.convertor.ts +6 -2
- package/src/brand-page-maker/convertors/text-size-value.convertor.test.ts +24 -0
- package/src/brand-page-maker/convertors/text-size-value.convertor.ts +17 -13
- package/src/brand-page-maker/default-getters/payment-text-and-border-color.default-getter.ts +7 -22
- package/src/brand-page-maker/default-getters/text-color.default-getter.ts +5 -21
- package/src/brand-page-maker/models/content-settings.test.ts +708 -0
- package/src/brand-page-maker/models/content-settings.ts +133 -82
- package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store-utils.test.ts +63 -1
- package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store-utils.ts +16 -3
- package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store.test.ts +34 -0
- package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store.ts +4 -2
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +185 -1
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +22 -34
- package/src/brand-page-maker/stores/history/history-store.ts +35 -2
- package/src/brand-page-maker/utils/__snapshots__/apply-color-strategy.golden.test.ts.snap +528 -0
- package/src/brand-page-maker/utils/__snapshots__/rte-render-parity.test.ts.snap +12 -0
- package/src/brand-page-maker/utils/apply-color-strategy.golden.test.ts +2 -0
- package/src/brand-page-maker/utils/apply-color-strategy.test.ts +181 -3
- package/src/brand-page-maker/utils/apply-color-strategy.ts +36 -4
- package/src/brand-page-maker/utils/index.ts +2 -1
- package/src/brand-page-maker/utils/rich-text-editor.util.test.ts +447 -410
- package/src/brand-page-maker/utils/rich-text-editor.util.ts +610 -506
- package/src/brand-page-maker/utils/rte-authoring.util.test.ts +244 -0
- package/src/brand-page-maker/utils/rte-authoring.util.ts +175 -0
- package/src/brand-page-maker/utils/rte-clipboard.util.test.ts +558 -0
- package/src/brand-page-maker/utils/rte-clipboard.util.ts +473 -0
- package/src/brand-page-maker/utils/rte-features.test.ts +99 -3
- package/src/brand-page-maker/utils/rte-render-parity.test.ts +1 -1
- package/src/brand-page-maker/utils/rte-render.util.test.ts +230 -0
- package/src/brand-page-maker/utils/rte-sanitize-json.test.ts +1 -1
- package/src/brand-page-maker/utils/rte-sanitize.util.ts +14 -3
- package/src/brand-page-maker/utils/rte-schema-version.test.ts +102 -0
- package/src/bundles/bundled-translations.de-DE.json +21 -2
- package/src/bundles/bundled-translations.es-ES.json +21 -2
- package/src/bundles/bundled-translations.fr-CA.json +21 -2
- package/src/bundles/bundled-translations.fr-FR.json +21 -2
- package/src/bundles/bundled-translations.json +21 -2
- package/src/bundles/bundled-translations.pt-BR.json +21 -2
- package/src/bundles/bundled-translations.pt-PT.json +21 -2
- package/src/clients/ai-assistant-client.ts +1 -0
- package/src/composables/useTranslate.ts +2 -1
- package/src/lib.ts +2 -2
- package/src/metadata-builder/builders/footer-builder.test.ts +70 -45
- package/src/metadata-builder/builders/footer-builder.ts +4 -8
- package/src/metadata-builder/builders/global-role-propagation.test.ts +907 -0
- package/src/metadata-builder/builders/global-role-propagation.ts +430 -0
- package/src/metadata-builder/builders/global-styles-builder.test.ts +1020 -0
- package/src/metadata-builder/builders/global-styles-builder.ts +194 -48
- package/src/metadata-builder/builders/header-builder.test.ts +112 -40
- package/src/metadata-builder/builders/header-builder.ts +18 -8
- package/src/metadata-builder/builders/section-builders/about-section-builder.ts +5 -3
- package/src/metadata-builder/builders/section-builders/banner-section-builder.ts +5 -3
- package/src/metadata-builder/builders/section-builders/booking-section-builder.ts +5 -3
- package/src/metadata-builder/builders/section-builders/contact-form-builder.ts +7 -4
- package/src/metadata-builder/builders/section-builders/images-section-builder.ts +5 -3
- package/src/metadata-builder/builders/section-builders/mailing-list-builder.ts +3 -2
- package/src/metadata-builder/builders/section-builders/mailing-list-section-builder.ts +3 -2
- package/src/metadata-builder/builders/section-builders/profile-section-builder.ts +7 -7
- package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +5 -3
- package/src/metadata-builder/builders/section-builders/social-links-builder.test.ts +2 -2
- package/src/metadata-builder/builders/section-builders/social-links-builder.ts +21 -10
- package/src/metadata-builder/builders/section-builders/support-me-builder.test.ts +10 -0
- package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +3 -2
- package/src/metadata-builder/builders/section-builders/text-section-builder.ts +111 -61
- package/src/metadata-builder/builders/section-field-maps.ts +1 -0
- package/src/metadata-builder/builders/section-field-utils.test.ts +545 -2
- package/src/metadata-builder/builders/section-field-utils.ts +202 -69
- package/src/metadata-builder/builders/section-rules/global-styles.rules.ts +38 -13
- package/src/metadata-builder/builders/section-rules/social-links.rules.ts +5 -0
- package/src/metadata-builder/helpers/rte.helpers.test.ts +101 -0
- package/src/metadata-builder/helpers/rte.helpers.ts +129 -43
- package/src/metadata-builder/metadata-executor.test.ts +167 -0
- package/src/metadata-builder/metadata-executor.ts +34 -1
- package/src/metadata-builder/models.ts +2 -0
- package/src/metadata-builder/parsers/ai-toolcall-parser.ts +23 -7
- package/src/metadata-builder/parsers/section-tool-arguments.ts +21 -1
- package/src/metadata-builder/sanitizers/__tests__/section-args-validator.test.ts +215 -0
- package/src/metadata-builder/sanitizers/rte-schema-check.ts +1 -1
- package/src/metadata-builder/sanitizers/sanitizer-rules.ts +4 -8
- package/src/metadata-builder/sanitizers/section-args-validator.ts +136 -53
- package/src/shared/color-palette/section-color-matches.test.ts +15 -11
- package/src/shared/color-palette/section-color-matches.ts +9 -28
- package/src/shared/color-strategies/color-strategies.ts +35 -0
- package/src/shared/color-strategies/rte-color.test.ts +1 -1
- package/src/shared/color-strategies/rte-color.ts +19 -0
- package/src/shared/color-strategies/rte-field-pairs.test.ts +26 -5
- package/src/shared/color-strategies/rte-field-pairs.ts +33 -0
- package/src/shared/content-settings/components/color-matches-panel/ColorMatchesPanel.test.ts +43 -66
- package/src/shared/content-settings/components/color-matches-panel/ColorMatchesPanel.vue +7 -1
- package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +1 -48
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +33 -7
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.test.ts +128 -1
- package/src/shared/content-settings/components/draggable-item-list/DraggableItemList.vue +1 -0
- package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.ts +0 -6
- package/src/shared/content-settings/components/logo-selection-field/LogoSelection.vue +3 -0
- package/src/shared/content-settings/components/logo-size-field/LogoSizeSlider.vue +3 -0
- package/src/shared/content-settings/components/logo-size-field/LogoSizeSliderField.vue +1 -0
- package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.vue +1 -0
- package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.test.ts +56 -3
- package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.ts +11 -4
- package/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.test.ts +335 -25
- package/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.ts +248 -70
- package/src/shared/content-settings/components/text-style-field/TextStyleField.vue +113 -25
- package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.de-DE.json +17 -10
- package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.es-ES.json +17 -10
- package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.fr-CA.json +17 -10
- package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.fr-FR.json +17 -10
- package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.json +8 -1
- package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.pt-BR.json +17 -10
- package/src/shared/content-settings/components/text-style-field/i18n/text-style-field.pt-PT.json +17 -10
- package/src/shared/content-settings/components/text-style-role-dropdown/TextStyleRoleDropdown.test.ts +141 -0
- package/src/shared/content-settings/components/text-style-role-dropdown/TextStyleRoleDropdown.vue +136 -0
- package/src/shared/content-settings/store/content-settings-store.test.ts +491 -6
- package/src/shared/content-settings/store/content-settings-store.ts +159 -17
- package/src/shared/logo-settings/components/EditLogoSettings.vue +1 -0
- package/src/shared/logo-settings/components/LogoVariations.vue +1 -0
- package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.vue +1 -0
- package/src/shared/navigation-style-settings/store/index.test.ts +295 -0
- package/src/shared/navigation-style-settings/store/index.ts +65 -15
- package/src/shared/page-settings/components/header-settings-panel/HeaderSettingsPanel.vue +2 -0
- package/src/shared/page-settings/components/page-settings/PageElement.vue +1 -0
- package/src/shared/page-settings/components/page-settings-section-styles/HeaderButtonSettings.test.ts +44 -4
- package/src/shared/page-settings/components/page-settings-section-styles/HeaderButtonSettings.vue +13 -4
- package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.navigation.test.ts +89 -0
- package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.text-style.test.ts +91 -0
- package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.ts +14 -2
- package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.vue +2 -0
- package/src/shared/page-settings/store/page-settings-store.text-style.test.ts +84 -0
- package/src/shared/page-settings/store/page-settings-store.ts +30 -1
- package/src/shared/rte-extensions/AutoLink.test.ts +98 -0
- package/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/AutoLink.ts +87 -58
- package/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/MaxLength.ts +4 -1
- package/src/shared/rte-extensions/TextEffects.ts +151 -0
- package/src/shared/rte-extensions/ViewDomParser.ts +27 -0
- package/src/{brand-page-maker/composables/rich-text-editor/getRteExtensions.ts → shared/rte-extensions.util.ts} +66 -9
- package/src/shared/rte-link.util.ts +2 -0
- package/src/shared/rte-render.util.ts +385 -0
- package/src/shared/rte-shape.util.ts +29 -0
- package/src/shared/side-bar/store/side-bar-store.test.ts +27 -1
- package/src/shared/side-bar/store/side-bar-store.ts +11 -0
- package/src/shared/style-settings/components/StyleSettings.mixin.ts +7 -3
- package/src/shared/style-settings/components/StyleSettings.test.ts +116 -0
- package/src/shared/style-settings/components/StyleSettings.vue +75 -25
- package/src/shared/style-settings/components/i18n/style-settings.de-DE.json +32 -20
- package/src/shared/style-settings/components/i18n/style-settings.es-ES.json +32 -20
- package/src/shared/style-settings/components/i18n/style-settings.fr-CA.json +32 -20
- package/src/shared/style-settings/components/i18n/style-settings.fr-FR.json +32 -20
- package/src/shared/style-settings/components/i18n/style-settings.json +13 -3
- package/src/shared/style-settings/components/i18n/style-settings.pt-BR.json +32 -20
- package/src/shared/style-settings/components/i18n/style-settings.pt-PT.json +32 -20
- package/src/shared/style-settings/components/text-style-options-settings-with-state/TextStyleOptionsSettingsWithState.vue +14 -34
- package/src/shared/style-settings/store/style-settings-store.ts +3 -49
- package/src/shared/style-settings/text-style-size-order.test.ts +76 -0
- package/src/shared/style-settings/text-style-size-order.ts +28 -0
- package/src/shared/template-settings/components/TemplatesSettings.vue +4 -0
- package/src/shared/text-role-typography.util.ts +277 -0
- package/src/utils/minify-brand-page-metadata.test.ts +102 -7
- package/src/utils/minify-brand-page-metadata.ts +62 -8
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/AutoLink.d.ts +0 -2
- package/lib/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.d.ts +0 -28
- package/lib/src/brand-page-maker/utils/rte-render.util.d.ts +0 -63
- package/lib/src/brand-page-maker/utils/rte-render.util.js +0 -106
- package/lib/src/brand-page-maker/utils/rte-shape.d.ts +0 -18
- package/lib/src/brand-page-maker/utils/rte-shape.js +0 -21
- package/lib/src/metadata-builder/builders/global-font-propagation.d.ts +0 -41
- package/lib/src/metadata-builder/builders/global-font-propagation.js +0 -146
- package/src/brand-page-maker/utils/rte-render.util.ts +0 -179
- package/src/brand-page-maker/utils/rte-shape.ts +0 -29
- package/src/metadata-builder/builders/global-font-propagation.test.ts +0 -401
- package/src/metadata-builder/builders/global-font-propagation.ts +0 -238
- package/src/shared/style-settings/components/StyleSettingsSection.vue +0 -8
- /package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/FontFamily.d.ts +0 -0
- /package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/FontFamily.js +0 -0
- /package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/LetterSpacing.d.ts +0 -0
- /package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/LetterSpacing.js +0 -0
- /package/lib/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/MaxLength.d.ts +0 -0
- /package/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/FontFamily.ts +0 -0
- /package/src/{brand-page-maker/composables/rich-text-editor/extensions → shared/rte-extensions}/LetterSpacing.ts +0 -0
|
@@ -8,7 +8,13 @@ import {
|
|
|
8
8
|
watch,
|
|
9
9
|
} from 'vue';
|
|
10
10
|
import { Editor } from '@tiptap/vue-3';
|
|
11
|
-
import { getRteExtensions } from '
|
|
11
|
+
import { getRteExtensions } from '@shared/rte-extensions.util';
|
|
12
|
+
import {
|
|
13
|
+
KeepMarksOnEmpty,
|
|
14
|
+
keepMarksOnEmptyPluginKey,
|
|
15
|
+
} from './keepMarksOnEmpty';
|
|
16
|
+
import { RoleTypographyFill } from './extensions/RoleTypographyFill';
|
|
17
|
+
import { RteClipboard } from './extensions/RteClipboard';
|
|
12
18
|
import type { StyleTextFontFamilyOption } from '@shared/style-settings/models';
|
|
13
19
|
import { createFormattingActions } from './formatting';
|
|
14
20
|
import { useTextAlign } from './textAlign';
|
|
@@ -18,8 +24,6 @@ import {
|
|
|
18
24
|
buildInitialMarks,
|
|
19
25
|
emToPx,
|
|
20
26
|
isSameRteContent,
|
|
21
|
-
isStyleChanged,
|
|
22
|
-
pxToEm,
|
|
23
27
|
sanitizeRteJson,
|
|
24
28
|
skipStyleDetection,
|
|
25
29
|
} from '@brand-page-maker/utils';
|
|
@@ -32,16 +36,28 @@ import {
|
|
|
32
36
|
import type { ButtonGroupOption } from '@brand-page-maker/models/button-group.model';
|
|
33
37
|
import { letterSpacingValueConvertor } from '@brand-page-maker/convertors';
|
|
34
38
|
import { useUiContentSettingsStore } from '@shared/content-settings/store';
|
|
39
|
+
import { useUiStyleSettingsStore } from '@shared/style-settings/store';
|
|
35
40
|
import { useHistoryStore } from '@brand-page-maker/stores/history/history-store';
|
|
36
41
|
import { AllSelection } from 'prosemirror-state';
|
|
42
|
+
import type { EditorState } from 'prosemirror-state';
|
|
43
|
+
import type { Mark } from 'prosemirror-model';
|
|
44
|
+
import { useUiColorPaletteStore } from '@shared/color-palette/store';
|
|
37
45
|
import { useHyperlink } from './hyperlink';
|
|
38
46
|
import { useBubbleMenu } from './bubbleMenu';
|
|
39
47
|
import {
|
|
40
48
|
hasLogoColorVar,
|
|
41
|
-
getRTEColor,
|
|
42
49
|
getToolbarColorFromMark,
|
|
43
50
|
resolveInitialToolbarTextColor,
|
|
51
|
+
hasRunTypographyOverride,
|
|
52
|
+
isCanonicalLinked,
|
|
53
|
+
isRoleVarRef,
|
|
54
|
+
mergePickedMarks,
|
|
55
|
+
normTypographyValue,
|
|
56
|
+
readBlockTypography,
|
|
57
|
+
relinkRoleEqualRunsChain,
|
|
58
|
+
relinkTypographyChain,
|
|
44
59
|
} from '@brand-page-maker/utils/rich-text-editor.util';
|
|
60
|
+
import { composeTextDecoration } from '@shared/text-role-typography.util';
|
|
45
61
|
import { useEventTracker, EVENTS } from '../useEventTracker';
|
|
46
62
|
|
|
47
63
|
interface UseRichTextEditorReturn {
|
|
@@ -63,12 +79,14 @@ interface UseRichTextEditorReturn {
|
|
|
63
79
|
}>;
|
|
64
80
|
toggleFont: (font: string) => void;
|
|
65
81
|
toggleFontSize: (size: string) => void;
|
|
66
|
-
letterSpacingValue:
|
|
67
|
-
lineHeightValue:
|
|
82
|
+
letterSpacingValue: WritableComputedRef<string>;
|
|
83
|
+
lineHeightValue: WritableComputedRef<string>;
|
|
68
84
|
selectedFont: ComputedRef<string>;
|
|
69
85
|
setInitialStyleSettings: (selectedTextStyle?: BrandPageCssStyle) => void;
|
|
70
|
-
|
|
71
|
-
|
|
86
|
+
hasTypographyOverride: () => boolean;
|
|
87
|
+
canApplyTypographyToRole: () => boolean;
|
|
88
|
+
resetTypographyToRole: () => void;
|
|
89
|
+
applyTypographyToRole: () => void;
|
|
72
90
|
handleHyperlink: (
|
|
73
91
|
action: 'toggle' | 'apply' | 'remove',
|
|
74
92
|
data?: { href?: string; text?: string },
|
|
@@ -100,6 +118,9 @@ interface EditorOptionType {
|
|
|
100
118
|
value: string | StyleTextFontFamilyOption;
|
|
101
119
|
}
|
|
102
120
|
|
|
121
|
+
// Outlasts the slowest debounced toolbar command (spacing, 300 ms). See undo-redo.md.
|
|
122
|
+
const USER_COMMAND_WINDOW_MS = 1000;
|
|
123
|
+
|
|
103
124
|
export const useExternalRichTextEditor = (): {
|
|
104
125
|
externalEditor: Editor;
|
|
105
126
|
} => {
|
|
@@ -135,12 +156,18 @@ export const useRichTextEditor = (
|
|
|
135
156
|
selectedFontSizePx: number;
|
|
136
157
|
selectedTextColor: string;
|
|
137
158
|
selectedBackgroundColor: string;
|
|
159
|
+
// BP-5969: bold/italic/underline/strike toolbar active-state, resolved from the effective
|
|
160
|
+
// textStyle attr OR a legacy semantic mark (set in selectionUpdate).
|
|
161
|
+
isBold: boolean;
|
|
162
|
+
isItalic: boolean;
|
|
163
|
+
isUnderline: boolean;
|
|
164
|
+
isStrike: boolean;
|
|
138
165
|
},
|
|
139
166
|
fontStyleDropdownRef: Ref<
|
|
140
167
|
DropdownInstance | undefined,
|
|
141
168
|
DropdownInstance | undefined
|
|
142
169
|
>,
|
|
143
|
-
//
|
|
170
|
+
// The selected role's entry of `textStyleOptions`.
|
|
144
171
|
selectedGlobalTextStyles: WritableComputedRef<
|
|
145
172
|
TextStyleOption | undefined,
|
|
146
173
|
string
|
|
@@ -153,17 +180,88 @@ export const useRichTextEditor = (
|
|
|
153
180
|
selectedLinkTypeValue: Ref<HyperlinkType>,
|
|
154
181
|
): UseRichTextEditorReturn => {
|
|
155
182
|
const historyStore = useHistoryStore();
|
|
183
|
+
const colorPaletteStore = useUiColorPaletteStore();
|
|
184
|
+
|
|
185
|
+
// A toolbar click moves focus off the editor before its command runs (Tiptap's `.focus()` restores
|
|
186
|
+
// it a frame later), so `isFocused` alone would file the user's edit as a mount write-back.
|
|
187
|
+
let userCommandUntil = 0;
|
|
188
|
+
|
|
189
|
+
const markUserCommand = (): void => {
|
|
190
|
+
userCommandUntil = Date.now() + USER_COMMAND_WINDOW_MS;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// The linked role's style for the var-or-literal write rule (BP-5969): a canonical-linked
|
|
194
|
+
// block resolves typography from its role, so a toolbar pick equal to the role is stored as
|
|
195
|
+
// the role var, not a literal. Undefined for legacy/unlinked blocks (they bake literals).
|
|
196
|
+
// Declared above the editor so RteClipboard's getContext (below) can close over it too.
|
|
197
|
+
const getRoleStyle = () =>
|
|
198
|
+
isCanonicalLinked(props.styles)
|
|
199
|
+
? selectedGlobalTextStyles.value?.style
|
|
200
|
+
: undefined;
|
|
201
|
+
|
|
202
|
+
// The first-type seed a genuinely fresh field takes, or the previous run's marks when the
|
|
203
|
+
// field was just cleared (KeepMarksOnEmpty's capture) — shared by `beforeinput` below and
|
|
204
|
+
// RteClipboard's text-only paste into an empty field, so a paste matches typing.
|
|
205
|
+
const getFirstInputMarks = (state: EditorState): Mark[] => {
|
|
206
|
+
const clearedMarks = keepMarksOnEmptyPluginKey.getState(state);
|
|
207
|
+
const pickedMarks = state.storedMarks;
|
|
208
|
+
|
|
209
|
+
if (clearedMarks && clearedMarks.length > 0) {
|
|
210
|
+
return mergePickedMarks(clearedMarks, pickedMarks);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const globalStyle = selectedGlobalTextStyles.value?.style;
|
|
214
|
+
// Element-first colour: see the matching comment in `beforeinput` below.
|
|
215
|
+
const styleSource = globalStyle
|
|
216
|
+
? { ...globalStyle, color: props.styles?.color }
|
|
217
|
+
: props.styles;
|
|
218
|
+
|
|
219
|
+
const marks = buildInitialMarks(
|
|
220
|
+
state,
|
|
221
|
+
styleSource,
|
|
222
|
+
!isCanonicalLinked(props.styles),
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
return mergePickedMarks(marks, pickedMarks);
|
|
226
|
+
};
|
|
156
227
|
|
|
157
228
|
const editor = new Editor({
|
|
158
229
|
content: model.value ?? '',
|
|
159
230
|
editable: !props.readOnly,
|
|
160
|
-
extensions:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
231
|
+
extensions: [
|
|
232
|
+
...getRteExtensions({
|
|
233
|
+
restrictStarterKit: true,
|
|
234
|
+
editing: {
|
|
235
|
+
placeholder: props.placeholder,
|
|
236
|
+
maxLength: props.maxLength,
|
|
237
|
+
},
|
|
238
|
+
}),
|
|
239
|
+
// Captures a cleared run's marks so the first-type seed below can restore the
|
|
240
|
+
// style on retype (rather than reseeding from the role).
|
|
241
|
+
KeepMarksOnEmpty,
|
|
242
|
+
RoleTypographyFill.configure({
|
|
243
|
+
getFillSource: () => {
|
|
244
|
+
const role = isCanonicalLinked(props.styles)
|
|
245
|
+
? selectedGlobalTextStyles.value?.style
|
|
246
|
+
: undefined;
|
|
247
|
+
|
|
248
|
+
return role
|
|
249
|
+
? {
|
|
250
|
+
role: role as unknown as Record<string, string>,
|
|
251
|
+
block: props.styles as unknown as Record<string, string>,
|
|
252
|
+
}
|
|
253
|
+
: undefined;
|
|
254
|
+
},
|
|
255
|
+
}),
|
|
256
|
+
RteClipboard.configure({
|
|
257
|
+
getContext: () => ({
|
|
258
|
+
role: getRoleStyle(),
|
|
259
|
+
block: props.styles,
|
|
260
|
+
colors: colorPaletteStore.colors,
|
|
261
|
+
}),
|
|
262
|
+
getFirstInputMarks,
|
|
263
|
+
}),
|
|
264
|
+
],
|
|
167
265
|
editorProps: {
|
|
168
266
|
handleDOMEvents: {
|
|
169
267
|
drop(view, event: DragEvent) {
|
|
@@ -173,109 +271,25 @@ export const useRichTextEditor = (
|
|
|
173
271
|
},
|
|
174
272
|
beforeinput(view, event) {
|
|
175
273
|
const { state } = view;
|
|
176
|
-
// On first insert into an empty doc, set storedMarks to global styles so all typed chars inherit them
|
|
177
274
|
|
|
178
275
|
if (
|
|
179
|
-
event.inputType
|
|
180
|
-
state.doc.textContent
|
|
276
|
+
event.inputType !== 'insertText' ||
|
|
277
|
+
state.doc.textContent !== ''
|
|
181
278
|
) {
|
|
182
|
-
|
|
183
|
-
// Element-first colour: once the doc is emptied, freshly-typed text must
|
|
184
|
-
// inherit a linked element's colour override (a creation-time contrast bake,
|
|
185
|
-
// or a colour picked while linked), not the linked global colour. Typography
|
|
186
|
-
// still comes from the global style (the element is linked), mirroring
|
|
187
|
-
// resolveTextColor's colour-only cascade.
|
|
188
|
-
const styleSource = globalStyle
|
|
189
|
-
? {
|
|
190
|
-
...globalStyle,
|
|
191
|
-
color: props.styles?.color || globalStyle.color,
|
|
192
|
-
}
|
|
193
|
-
: props.styles;
|
|
194
|
-
|
|
195
|
-
const marks = buildInitialMarks(state, styleSource);
|
|
196
|
-
|
|
197
|
-
const chain = editor.chain();
|
|
198
|
-
|
|
199
|
-
if (props.styles.textAlign)
|
|
200
|
-
chain.setTextAlign(props.styles.textAlign);
|
|
201
|
-
|
|
202
|
-
skipStyleDetection(chain, marks).run();
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
return false;
|
|
206
|
-
},
|
|
207
|
-
copy(view, event: ClipboardEvent) {
|
|
208
|
-
const selection = view.state.selection;
|
|
209
|
-
|
|
210
|
-
if (selection.empty) return;
|
|
211
|
-
|
|
212
|
-
const data = event.clipboardData;
|
|
213
|
-
|
|
214
|
-
const styleData = JSON.stringify(props.styles);
|
|
215
|
-
|
|
216
|
-
const slice = selection.content(),
|
|
217
|
-
{ dom, text } = view.serializeForClipboard(slice);
|
|
218
|
-
|
|
219
|
-
if (data) {
|
|
220
|
-
event.preventDefault();
|
|
221
|
-
data.clearData();
|
|
222
|
-
data.setData('text/html', dom.innerHTML);
|
|
223
|
-
data.setData('text/plain', text);
|
|
224
|
-
|
|
225
|
-
if (styleData) data.setData('application/x-rte-styles', styleData);
|
|
279
|
+
return false;
|
|
226
280
|
}
|
|
227
281
|
|
|
228
|
-
|
|
229
|
-
},
|
|
230
|
-
|
|
231
|
-
paste(view, event) {
|
|
232
|
-
// Unified paste handler: strip styles if no styleData, enforce maxLength, handle selection
|
|
233
|
-
const styleData = event.clipboardData?.getData(
|
|
234
|
-
'application/x-rte-styles',
|
|
235
|
-
);
|
|
236
|
-
const pastedText = event.clipboardData?.getData('text/plain') || '';
|
|
237
|
-
const { state, dispatch } = view;
|
|
238
|
-
const { from, to } = state.selection;
|
|
239
|
-
|
|
240
|
-
let tr = state.tr;
|
|
241
|
-
|
|
242
|
-
if (styleData) {
|
|
243
|
-
try {
|
|
244
|
-
const pastedStyles = JSON.parse(styleData);
|
|
245
|
-
const fontStyleChanges: TextStyleDeclaration = {
|
|
246
|
-
color: pastedStyles.color,
|
|
247
|
-
fontFamily: pastedStyles.fontFamily,
|
|
248
|
-
fontSize: pastedStyles.fontSize,
|
|
249
|
-
fontWeight: pastedStyles.fontWeight,
|
|
250
|
-
fontStyle: pastedStyles.fontStyle,
|
|
251
|
-
textDecoration: pastedStyles.textDecoration,
|
|
252
|
-
lineHeight: pastedStyles.lineHeight,
|
|
253
|
-
letterSpacing: pastedStyles.letterSpacing,
|
|
254
|
-
textAlign: pastedStyles.textAlign,
|
|
255
|
-
backgroundColor: pastedStyles.backgroundColor,
|
|
256
|
-
textStyleType: undefined,
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
syncContentSettings(fontStyleChanges);
|
|
260
|
-
|
|
261
|
-
return false;
|
|
262
|
-
} catch {
|
|
263
|
-
// ignore malformed styleData
|
|
264
|
-
}
|
|
265
|
-
} else {
|
|
266
|
-
event.preventDefault();
|
|
267
|
-
tr.delete(from, to);
|
|
268
|
-
|
|
269
|
-
const createdMarks = buildInitialMarks(state, props.styles);
|
|
270
|
-
|
|
271
|
-
tr = tr.setStoredMarks(createdMarks).insertText(pastedText, from);
|
|
282
|
+
const chain = editor.chain();
|
|
272
283
|
|
|
273
|
-
|
|
274
|
-
|
|
284
|
+
// textAlign is a block-node attr, not a mark, and a full clear resets it — so
|
|
285
|
+
// re-apply the element's alignment regardless of which seed `getFirstInputMarks`
|
|
286
|
+
// takes below (it's the one thing that survives a full clear).
|
|
287
|
+
if (props.styles.textAlign)
|
|
288
|
+
chain.setTextAlign(props.styles.textAlign);
|
|
275
289
|
|
|
276
|
-
|
|
290
|
+
skipStyleDetection(chain, getFirstInputMarks(state)).run();
|
|
277
291
|
|
|
278
|
-
return
|
|
292
|
+
return false;
|
|
279
293
|
},
|
|
280
294
|
click(view, event) {
|
|
281
295
|
if (isHyperlinkPopupOpen?.value) return false;
|
|
@@ -303,6 +317,7 @@ export const useRichTextEditor = (
|
|
|
303
317
|
});
|
|
304
318
|
|
|
305
319
|
const contentSettingStore = useUiContentSettingsStore();
|
|
320
|
+
const styleSettingsStore = useUiStyleSettingsStore();
|
|
306
321
|
const eventTracker = useEventTracker();
|
|
307
322
|
|
|
308
323
|
const {
|
|
@@ -312,13 +327,11 @@ export const useRichTextEditor = (
|
|
|
312
327
|
toggleStrike,
|
|
313
328
|
toggleTextColor,
|
|
314
329
|
toggleBackgroundColor,
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
unsetAllMarks,
|
|
321
|
-
} = createFormattingActions(editor);
|
|
330
|
+
boldActive,
|
|
331
|
+
italicActive,
|
|
332
|
+
underlineActive,
|
|
333
|
+
strikeActive,
|
|
334
|
+
} = createFormattingActions(editor, getRoleStyle, () => props.styles);
|
|
322
335
|
|
|
323
336
|
const {
|
|
324
337
|
currentAlignment,
|
|
@@ -327,22 +340,37 @@ export const useRichTextEditor = (
|
|
|
327
340
|
keys: alignmentKeys,
|
|
328
341
|
} = useTextAlign(editor);
|
|
329
342
|
|
|
330
|
-
const {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
} = useFont(editor, fontSettings, fontStyleDropdownRef);
|
|
343
|
+
const { selectedFont, toggleFont, toggleFontSize } = useFont(
|
|
344
|
+
editor,
|
|
345
|
+
fontSettings,
|
|
346
|
+
fontStyleDropdownRef,
|
|
347
|
+
getRoleStyle,
|
|
348
|
+
);
|
|
337
349
|
|
|
338
350
|
const {
|
|
339
|
-
letterSpacingValue,
|
|
340
|
-
lineHeightValue,
|
|
351
|
+
letterSpacingValue: letterSpacingSlider,
|
|
352
|
+
lineHeightValue: lineHeightSlider,
|
|
341
353
|
letterSpacing,
|
|
342
354
|
lineHeight,
|
|
343
355
|
setLetterSpaceAll,
|
|
344
356
|
setLineHeightAll,
|
|
345
|
-
} = useSpacing(editor);
|
|
357
|
+
} = useSpacing(editor, getRoleStyle);
|
|
358
|
+
|
|
359
|
+
const letterSpacingValue = computed<string>({
|
|
360
|
+
get: () => letterSpacingSlider.value,
|
|
361
|
+
set: (value) => {
|
|
362
|
+
markUserCommand();
|
|
363
|
+
letterSpacingSlider.value = value;
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
const lineHeightValue = computed<string>({
|
|
368
|
+
get: () => lineHeightSlider.value,
|
|
369
|
+
set: (value) => {
|
|
370
|
+
markUserCommand();
|
|
371
|
+
lineHeightSlider.value = value;
|
|
372
|
+
},
|
|
373
|
+
});
|
|
346
374
|
|
|
347
375
|
const {
|
|
348
376
|
hyperlinkValue,
|
|
@@ -410,121 +438,123 @@ export const useRichTextEditor = (
|
|
|
410
438
|
},
|
|
411
439
|
);
|
|
412
440
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
441
|
+
// BP-5969 (ADR-0019): the auto-detach that cleared `textStyleType` whenever the doc's
|
|
442
|
+
// style changed is gone — a style edit is now a per-run mark and the block keeps its
|
|
443
|
+
// role. (Was: `editor.on('transaction')` → `onSelectTextStyleType('None')`.)
|
|
444
|
+
|
|
445
|
+
// Refresh the B/I/U/S button state from the effective formatting (textStyle attr, resolved
|
|
446
|
+
// against the role, OR a legacy semantic mark). It runs on every transaction: a format picked with
|
|
447
|
+
// nothing selected only sets a stored mark, which fires neither `update` nor `selectionUpdate`.
|
|
448
|
+
const syncFormattingActiveState = () => {
|
|
449
|
+
fontSettings.isBold = boldActive();
|
|
450
|
+
fontSettings.isItalic = italicActive();
|
|
451
|
+
fontSettings.isUnderline = underlineActive();
|
|
452
|
+
fontSettings.isStrike = strikeActive();
|
|
453
|
+
};
|
|
421
454
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
455
|
+
// Skipped while a history snapshot applies, as `selectionUpdate` is (BP-5506).
|
|
456
|
+
editor.on('transaction', () => {
|
|
457
|
+
if (historyStore.isApplyingSnapshot) return;
|
|
458
|
+
|
|
459
|
+
syncFormattingActiveState();
|
|
427
460
|
});
|
|
428
461
|
|
|
462
|
+
// A role edit (Style tab, AI) reaches the editor without a transaction. An empty one repaints
|
|
463
|
+
// the B/I/U/S state and the box's role fill (`RoleTypographyFill`) without touching the doc.
|
|
464
|
+
watch(
|
|
465
|
+
() => selectedGlobalTextStyles.value?.style,
|
|
466
|
+
() => {
|
|
467
|
+
if (editor.isDestroyed) return;
|
|
468
|
+
|
|
469
|
+
editor.view.dispatch(editor.state.tr.setMeta('addToHistory', false));
|
|
470
|
+
},
|
|
471
|
+
{ deep: true },
|
|
472
|
+
);
|
|
473
|
+
|
|
429
474
|
// Update model when editor content changes. RTE content is stored as Tiptap
|
|
430
475
|
// JSON (BP-5787). getJSON() is already in hand (the editor holds the doc) and
|
|
431
476
|
// is sanitised natively — no getHTML(), no DOMPurify, no extra editor — so
|
|
432
477
|
// the per-keystroke path allocates nothing heavy.
|
|
433
478
|
editor.on('update', () => {
|
|
434
|
-
// An update fired while the editor is unfocused is
|
|
435
|
-
// model
|
|
436
|
-
// programmatic setContent — not a user edit. Tag the emit so the write
|
|
437
|
-
//
|
|
438
|
-
//
|
|
439
|
-
//
|
|
440
|
-
//
|
|
441
|
-
// debounce fires. Genuine edits happen while focused and commit
|
|
442
|
-
// normally.
|
|
443
|
-
//
|
|
444
|
-
// Known limitation: a programmatic toolbar command run on an editor the
|
|
445
|
-
// user hasn't focused yet would also merge (losing that undo step). Today
|
|
446
|
-
// the RTE only mounts inside an already-open settings drawer and the user
|
|
447
|
-
// focuses it before formatting, so this doesn't occur — revisit if a
|
|
448
|
-
// consumer ever drives toolbar actions on an unfocused editor.
|
|
479
|
+
// An update fired while the editor is unfocused and no toolbar command is in flight is
|
|
480
|
+
// TipTap rewriting the model into its canonical form during mount rehydration or a
|
|
481
|
+
// programmatic setContent — not a user edit. Tag the emit so the write folds into the
|
|
482
|
+
// current undo head instead of pushing a phantom entry (BP-5810). The flag travels WITH
|
|
483
|
+
// the value through the debounced field → store chain and arms the history merge at the
|
|
484
|
+
// moment of the store write — arming here at emit time would lapse before the debounce
|
|
485
|
+
// fires. Typing (focused) and toolbar commands (`markUserCommand`) commit normally.
|
|
449
486
|
emit('update:modelValue', sanitizeRteJson(editor.getJSON()), {
|
|
450
|
-
isHydrationWrite: !editor.isFocused,
|
|
487
|
+
isHydrationWrite: !editor.isFocused && Date.now() > userCommandUntil,
|
|
451
488
|
});
|
|
452
489
|
});
|
|
453
490
|
|
|
454
|
-
editor
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
491
|
+
// The toolbar's read of the editor at the cursor: a mark holding a role var (or no mark) shows the
|
|
492
|
+
// linked role's value, a literal shows itself. Colours fall back to the given values when the run
|
|
493
|
+
// has none, so the mount-time seed can pass the element colour it resolved.
|
|
494
|
+
const syncToolbarFromEditor = ({
|
|
495
|
+
textColorFallback = '#000000',
|
|
496
|
+
backgroundColorFallback = 'transparent',
|
|
497
|
+
}: {
|
|
498
|
+
textColorFallback?: string;
|
|
499
|
+
backgroundColorFallback?: string;
|
|
500
|
+
} = {}): void => {
|
|
462
501
|
const textStyleAttributes = editor.getAttributes('textStyle');
|
|
463
502
|
const highlightAttributes = editor.getAttributes('highlight');
|
|
464
503
|
const focusedAlignment = editor.getAttributes(
|
|
465
504
|
editor.state.selection.$anchor.node().type.name,
|
|
466
505
|
);
|
|
467
506
|
|
|
468
|
-
const
|
|
507
|
+
const roleStyle = getRoleStyle();
|
|
469
508
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
to: selection.to - 1,
|
|
476
|
-
});
|
|
477
|
-
}
|
|
509
|
+
const markFontFamily = textStyleAttributes?.fontFamily;
|
|
510
|
+
const displayFont =
|
|
511
|
+
markFontFamily && !isRoleVarRef(markFontFamily)
|
|
512
|
+
? markFontFamily.replace(/^['"]|['"]$/g, '')
|
|
513
|
+
: (roleStyle?.fontFamily ?? 'Lato');
|
|
478
514
|
|
|
479
|
-
|
|
480
|
-
|
|
515
|
+
selectedFont.value = displayFont;
|
|
516
|
+
fontSettings.selectedFont = displayFont;
|
|
481
517
|
|
|
482
|
-
|
|
483
|
-
|
|
518
|
+
const markFontSize = textStyleAttributes?.fontSize;
|
|
519
|
+
const sizeSource =
|
|
520
|
+
markFontSize && !isRoleVarRef(markFontSize)
|
|
521
|
+
? markFontSize
|
|
522
|
+
: (roleStyle?.fontSize ?? fontSettings.selectedFontSize);
|
|
484
523
|
|
|
485
|
-
|
|
486
|
-
fontSettings.selectedFont = font;
|
|
487
|
-
} else {
|
|
488
|
-
selectedFont.value = 'Lato';
|
|
489
|
-
fontSettings.selectedFont = 'Lato';
|
|
490
|
-
}
|
|
524
|
+
fontSettings.selectedFontSizePx = Math.ceil(parseFloat(emToPx(sizeSource)));
|
|
491
525
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
parseFloat(emToPx(textStyleAttributes.fontSize)),
|
|
495
|
-
);
|
|
496
|
-
} else {
|
|
497
|
-
fontSettings.selectedFontSizePx = Math.ceil(
|
|
498
|
-
parseFloat(emToPx(fontSettings.selectedFontSize)),
|
|
499
|
-
);
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// Reflect the active mark colour on the toolbar. A palette reference is kept
|
|
503
|
-
// verbatim (so ColorField can highlight the swatch); a literal is hex-normalised —
|
|
504
|
-
// Color().hex() throws on a var(), so the split lives in getToolbarColorFromMark.
|
|
526
|
+
// A palette reference is kept verbatim (so ColorField can highlight the swatch); a literal is
|
|
527
|
+
// hex-normalised — Color().hex() throws on a var(), so the split lives in getToolbarColorFromMark.
|
|
505
528
|
fontSettings.selectedTextColor = getToolbarColorFromMark(
|
|
506
529
|
textStyleAttributes?.color,
|
|
507
|
-
|
|
530
|
+
textColorFallback,
|
|
508
531
|
);
|
|
509
532
|
|
|
510
533
|
fontSettings.selectedBackgroundColor = getToolbarColorFromMark(
|
|
511
534
|
highlightAttributes?.color,
|
|
512
|
-
|
|
535
|
+
backgroundColorFallback,
|
|
513
536
|
);
|
|
514
537
|
|
|
515
|
-
|
|
516
|
-
lineHeight.value = textStyleAttributes.lineHeight;
|
|
517
|
-
} else {
|
|
518
|
-
lineHeight.value = '1';
|
|
519
|
-
}
|
|
538
|
+
syncFormattingActiveState();
|
|
520
539
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
540
|
+
const markLineHeight = textStyleAttributes.lineHeight;
|
|
541
|
+
|
|
542
|
+
lineHeight.value =
|
|
543
|
+
markLineHeight && !isRoleVarRef(markLineHeight)
|
|
544
|
+
? markLineHeight
|
|
545
|
+
: (roleStyle?.lineHeight ?? '1');
|
|
546
|
+
|
|
547
|
+
const markLetterSpacing = textStyleAttributes?.letterSpacing;
|
|
548
|
+
const letterSpacingSource =
|
|
549
|
+
markLetterSpacing && !isRoleVarRef(markLetterSpacing)
|
|
550
|
+
? markLetterSpacing
|
|
551
|
+
: roleStyle?.letterSpacing;
|
|
552
|
+
|
|
553
|
+
letterSpacing.value = letterSpacingSource
|
|
554
|
+
? letterSpacingValueConvertor.convert({
|
|
555
|
+
letterSpacing: letterSpacingSource,
|
|
556
|
+
})
|
|
557
|
+
: '0';
|
|
528
558
|
|
|
529
559
|
if (focusedAlignment && focusedAlignment.textAlign) {
|
|
530
560
|
const idx = alignmentKeys.indexOf(focusedAlignment.textAlign);
|
|
@@ -535,6 +565,31 @@ export const useRichTextEditor = (
|
|
|
535
565
|
} else {
|
|
536
566
|
currentAlignmentIndex.value = 0;
|
|
537
567
|
}
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
editor.on('selectionUpdate', () => {
|
|
571
|
+
// Skip while a history snapshot is being applied — `setContent` fires
|
|
572
|
+
// selectionUpdate before the editor has fully rehydrated, which causes
|
|
573
|
+
// toolbar buttons (alignment, letter-spacing) to flash through bogus
|
|
574
|
+
// active states before settling. The editor emits a final selectionUpdate
|
|
575
|
+
// after apply completes, which lands the correct values (BP-5506).
|
|
576
|
+
if (historyStore.isApplyingSnapshot) return;
|
|
577
|
+
|
|
578
|
+
const selection = editor.state.selection;
|
|
579
|
+
|
|
580
|
+
if (selection instanceof AllSelection) {
|
|
581
|
+
// to prevent selecting editor state
|
|
582
|
+
// when user presses ctrl + a the beforeinput event doesn't get triggered
|
|
583
|
+
editor.commands.setTextSelection({
|
|
584
|
+
from: selection.from + 1,
|
|
585
|
+
to: selection.to - 1,
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// TODO: resolve the issue of missing style on text between empty lines
|
|
590
|
+
// retainStyleOnEmptyLine(editor, selection);
|
|
591
|
+
|
|
592
|
+
syncToolbarFromEditor();
|
|
538
593
|
});
|
|
539
594
|
|
|
540
595
|
const setInitialStyleSettings = (selectedTextStyle?: BrandPageCssStyle) => {
|
|
@@ -546,6 +601,14 @@ export const useRichTextEditor = (
|
|
|
546
601
|
);
|
|
547
602
|
|
|
548
603
|
if (globalStyles) {
|
|
604
|
+
// A canonical-linked block inherits typography from the role CSS class and stores
|
|
605
|
+
// only its per-property OVERRIDES (BP-5969). Re-deriving the role's typography onto
|
|
606
|
+
// the element on every RTE mount clobbered those overrides — selecting a block
|
|
607
|
+
// reverted its title to the role font/size — so bake typography here only for
|
|
608
|
+
// legacy/unlinked blocks (which still carry the resolved style inline). Mirrors the
|
|
609
|
+
// isCanonicalLinked gate in buildInitialMarks / getUpdatedHTMLFromEditor.
|
|
610
|
+
const bakeTypography = !isCanonicalLinked(props.styles);
|
|
611
|
+
|
|
549
612
|
// sync content settings style — a mount-time re-derivation, not a user
|
|
550
613
|
// edit. Flag it so the store folds it into the current undo head: this
|
|
551
614
|
// write lands ~100ms BEFORE the editor's canonical text write-back, and
|
|
@@ -555,38 +618,46 @@ export const useRichTextEditor = (
|
|
|
555
618
|
id: props.rawId,
|
|
556
619
|
name: props.name,
|
|
557
620
|
value: {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
621
|
+
...(bakeTypography
|
|
622
|
+
? {
|
|
623
|
+
fontSize: globalStyles.fontSize,
|
|
624
|
+
fontFamily: globalStyles.fontFamily,
|
|
625
|
+
fontWeight: globalStyles.fontWeight,
|
|
626
|
+
fontStyle: globalStyles.fontStyle,
|
|
627
|
+
textDecoration: globalStyles.textDecoration,
|
|
628
|
+
lineHeight: globalStyles.lineHeight,
|
|
629
|
+
letterSpacing: globalStyles.letterSpacing,
|
|
630
|
+
}
|
|
631
|
+
: {}),
|
|
632
|
+
// The element's own colour override (a creation-time contrast bake, or a colour
|
|
633
|
+
// picked while linked). ADR-0020: the role carries no colour, so there is no
|
|
634
|
+
// global fallback — an uncoloured element renders the page base coat.
|
|
635
|
+
color: props.styles?.color,
|
|
571
636
|
},
|
|
572
637
|
isHydrationWrite: !editor.isFocused,
|
|
573
638
|
});
|
|
574
639
|
|
|
575
|
-
// sync toolbar editor styles
|
|
576
|
-
|
|
577
|
-
|
|
640
|
+
// sync toolbar editor styles — show the block's EFFECTIVE typography (its override,
|
|
641
|
+
// else the linked role) so the toolbar matches the render, not the role blindly.
|
|
642
|
+
const effectiveFontSize =
|
|
643
|
+
props.styles?.fontSize ?? globalStyles?.fontSize ?? '2.25em';
|
|
644
|
+
|
|
645
|
+
fontSettings.selectedFont =
|
|
646
|
+
props.styles?.fontFamily ?? globalStyles?.fontFamily ?? 'Lato';
|
|
647
|
+
fontSettings.selectedFontSize = effectiveFontSize;
|
|
578
648
|
fontSettings.selectedFontSizePx = Math.ceil(
|
|
579
|
-
parseFloat(emToPx(
|
|
649
|
+
parseFloat(emToPx(effectiveFontSize)),
|
|
580
650
|
);
|
|
581
651
|
// For an RTE field the mark is the source of truth — the render and the focus-time
|
|
582
652
|
// `selectionUpdate` both paint from it — so seed the swatch from the mark's first
|
|
583
653
|
// coloured run, falling back to the element→global cascade. Otherwise the unfocused
|
|
584
654
|
// swatch shows the linked global while the text renders its baked frame/override
|
|
585
655
|
// colour, and only snaps to the right colour on focus (BP-5886).
|
|
656
|
+
// BP-5969 (ADR-0020): the role contributes no colour — seed the swatch from the RTE
|
|
657
|
+
// mark, else the element's own colour.
|
|
586
658
|
fontSettings.selectedTextColor = resolveInitialToolbarTextColor(
|
|
587
659
|
model.value,
|
|
588
660
|
props.styles?.color,
|
|
589
|
-
globalStyles.color,
|
|
590
661
|
);
|
|
591
662
|
// A global text style has no backgroundColor, so this resolves to undefined there.
|
|
592
663
|
const backgroundColour =
|
|
@@ -612,83 +683,31 @@ export const useRichTextEditor = (
|
|
|
612
683
|
) {
|
|
613
684
|
toggleTextAlign(props.styles.textAlign);
|
|
614
685
|
}
|
|
615
|
-
} else if (props.styles) {
|
|
616
|
-
// copy the content settings styles to the editor
|
|
617
|
-
fontSettings.selectedFont = props.styles?.fontFamily ?? 'Lato';
|
|
618
|
-
fontSettings.selectedFontSize = props.styles?.fontSize ?? '2.25em';
|
|
619
|
-
fontSettings.selectedFontSizePx = Math.ceil(
|
|
620
|
-
parseFloat(emToPx(props.styles?.fontSize ?? '2.25em')),
|
|
621
|
-
);
|
|
622
|
-
// No linked global (props.styles carries no textStyleType) — still resolve the RTE
|
|
623
|
-
// mark first, so a field whose colour lives only in its mark (e.g. the tipping/payment
|
|
624
|
-
// success message, which has no style object) shows it instead of collapsing to black.
|
|
625
|
-
fontSettings.selectedTextColor = resolveInitialToolbarTextColor(
|
|
626
|
-
model.value,
|
|
627
|
-
props.styles?.color,
|
|
628
|
-
);
|
|
629
|
-
fontSettings.selectedBackgroundColor = hasLogoColorVar(
|
|
630
|
-
props.styles?.backgroundColor ?? '',
|
|
631
|
-
)
|
|
632
|
-
? 'transparent'
|
|
633
|
-
: (props.styles?.backgroundColor ?? 'transparent');
|
|
634
|
-
lineHeight.value = props.styles?.lineHeight?.includes('em')
|
|
635
|
-
? emToPx(props.styles?.lineHeight ?? '1em')
|
|
636
|
-
: (props.styles?.lineHeight ?? '1');
|
|
637
|
-
letterSpacing.value = letterSpacingValueConvertor.convert(
|
|
638
|
-
props.styles ?? {},
|
|
639
|
-
);
|
|
640
|
-
|
|
641
|
-
if (
|
|
642
|
-
props.styles?.textAlign &&
|
|
643
|
-
currentAlignment?.textAlign !== props.styles.textAlign
|
|
644
|
-
) {
|
|
645
|
-
toggleTextAlign(props.styles.textAlign);
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
};
|
|
649
|
-
|
|
650
|
-
const copyGlobalStyleSettings = (selectedTextStyle?: BrandPageCssStyle) => {
|
|
651
|
-
const globalStyles =
|
|
652
|
-
selectedTextStyle ?? selectedGlobalTextStyles.value?.style;
|
|
653
|
-
|
|
654
|
-
if (globalStyles) {
|
|
655
|
-
globalStyles.fontWeight === 'bold' && toggleBoldAll();
|
|
656
|
-
globalStyles.fontStyle && toggleItalicAll();
|
|
657
|
-
globalStyles.textDecoration?.includes('underline') &&
|
|
658
|
-
toggleUnderlineAll();
|
|
659
|
-
globalStyles.textDecoration?.includes('line-through') &&
|
|
660
|
-
toggleStrikeAll();
|
|
661
|
-
|
|
662
|
-
if (globalStyles.color) {
|
|
663
|
-
if (!hasLogoColorVar(globalStyles.color)) {
|
|
664
|
-
toggleTextColorAll(globalStyles.color);
|
|
665
|
-
fontSettings.selectedTextColor = globalStyles.color;
|
|
666
|
-
} else {
|
|
667
|
-
// Apply logo color using CSS variable
|
|
668
|
-
toggleTextColorAll(getRTEColor(globalStyles.color, 'text'));
|
|
669
|
-
fontSettings.selectedTextColor = '#000000';
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
686
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
props.styles.textAlign &&
|
|
679
|
-
toggleTextAlign(props.styles.textAlign ?? 'none');
|
|
687
|
+
// Show the runs' own values (the role, or a per-run override) before the first click.
|
|
688
|
+
syncToolbarFromEditor({
|
|
689
|
+
textColorFallback: fontSettings.selectedTextColor,
|
|
690
|
+
backgroundColorFallback: fontSettings.selectedBackgroundColor,
|
|
691
|
+
});
|
|
680
692
|
}
|
|
681
693
|
};
|
|
682
694
|
|
|
695
|
+
// BP-5969 (ADR-0019): a toolbar edit applies a TipTap mark ONLY. The old sync wrote
|
|
696
|
+
// the flattened style back onto the block object AND cleared its role link
|
|
697
|
+
// (`textStyleType: undefined`) — that dual source of truth is the "a per-run colour
|
|
698
|
+
// edit repaints the whole block / drops the role" bug class. Now per-run formatting
|
|
699
|
+
// lives on marks; the block stays linked; whole-box size/family are authored from the
|
|
700
|
+
// sidebar. Alignment is the one block-level toolbar action, so it still persists — but
|
|
701
|
+
// without detaching the role.
|
|
683
702
|
const triggerEditorStyleChange = (editorOption: EditorOptionType) => {
|
|
684
|
-
|
|
703
|
+
markUserCommand();
|
|
685
704
|
|
|
686
705
|
switch (editorOption.type) {
|
|
687
706
|
case 'fontFamily':
|
|
688
707
|
toggleFont(editorOption.value as string);
|
|
689
|
-
fontStyleChanges.fontFamily = editorOption.value as string;
|
|
690
708
|
break;
|
|
691
|
-
|
|
709
|
+
|
|
710
|
+
case 'fontSize': {
|
|
692
711
|
const size = editorOption.value as string;
|
|
693
712
|
|
|
694
713
|
fontSettings.selectedFontSizePx = size.includes('em')
|
|
@@ -696,93 +715,168 @@ export const useRichTextEditor = (
|
|
|
696
715
|
: parseInt(size);
|
|
697
716
|
|
|
698
717
|
toggleFontSize(size);
|
|
699
|
-
fontStyleChanges.fontSize = size.includes('em') ? size : pxToEm(size);
|
|
700
718
|
break;
|
|
719
|
+
}
|
|
720
|
+
|
|
701
721
|
case 'fontWeight':
|
|
702
722
|
toggleBold();
|
|
703
|
-
editor.isActive('bold')
|
|
704
|
-
? (fontStyleChanges.fontWeight = 'bold')
|
|
705
|
-
: (fontStyleChanges.fontWeight = undefined);
|
|
706
723
|
break;
|
|
707
724
|
case 'fontStyle':
|
|
708
725
|
toggleItalic();
|
|
709
|
-
editor.isActive('italic')
|
|
710
|
-
? (fontStyleChanges.fontStyle = 'italic')
|
|
711
|
-
: (fontStyleChanges.fontStyle = undefined);
|
|
712
726
|
break;
|
|
713
727
|
case 'textDecorationLine':
|
|
714
728
|
toggleUnderline();
|
|
715
|
-
editor.isActive('underline')
|
|
716
|
-
? fontStyleChanges.textDecoration
|
|
717
|
-
? (fontStyleChanges.textDecoration =
|
|
718
|
-
fontStyleChanges.textDecoration + ' underline')
|
|
719
|
-
: (fontStyleChanges.textDecoration = 'underline')
|
|
720
|
-
: (fontStyleChanges.textDecoration =
|
|
721
|
-
fontStyleChanges.textDecoration?.replace('underline', ''));
|
|
722
|
-
|
|
723
729
|
break;
|
|
724
730
|
case 'textDecorationStrike':
|
|
725
731
|
toggleStrike();
|
|
726
|
-
editor.isActive('strike')
|
|
727
|
-
? fontStyleChanges.textDecoration
|
|
728
|
-
? (fontStyleChanges.textDecoration =
|
|
729
|
-
fontStyleChanges.textDecoration + ' line-through')
|
|
730
|
-
: (fontStyleChanges.textDecoration = 'line-through')
|
|
731
|
-
: (fontStyleChanges.textDecoration =
|
|
732
|
-
fontStyleChanges.textDecoration?.replace('line-through', ''));
|
|
733
732
|
break;
|
|
734
733
|
case 'textColor':
|
|
735
734
|
toggleTextColor(editorOption.value as string);
|
|
736
|
-
fontStyleChanges.color = editorOption.value as string;
|
|
737
735
|
break;
|
|
738
736
|
case 'backgroundColor':
|
|
739
737
|
toggleBackgroundColor(editorOption.value as string);
|
|
740
|
-
fontStyleChanges.backgroundColor = editorOption.value as string;
|
|
741
738
|
break;
|
|
742
739
|
case 'lineHeight':
|
|
743
740
|
setLineHeightAll(editorOption.value as string);
|
|
744
|
-
fontStyleChanges.lineHeight = editorOption.value as string;
|
|
745
741
|
break;
|
|
746
742
|
case 'letterSpacing':
|
|
747
743
|
setLetterSpaceAll(editorOption.value as string);
|
|
748
|
-
fontStyleChanges.letterSpacing = letterSpacingValueConvertor.convert({
|
|
749
|
-
letterSpacing: editorOption.value as string,
|
|
750
|
-
});
|
|
751
744
|
break;
|
|
752
745
|
case 'textAlign':
|
|
753
746
|
toggleTextAlign();
|
|
754
|
-
|
|
747
|
+
persistBlockTextAlign(currentAlignment.value.alignment);
|
|
755
748
|
break;
|
|
756
749
|
case 'hyperlink':
|
|
757
750
|
setHyperlinkUrl(editorOption.value as string);
|
|
758
751
|
break;
|
|
759
752
|
}
|
|
760
|
-
|
|
761
|
-
syncContentSettings(fontStyleChanges);
|
|
762
753
|
};
|
|
763
754
|
|
|
764
|
-
|
|
755
|
+
// Alignment is block-level (not a per-run mark, not a role property), so it persists to
|
|
756
|
+
// the block/item style — writing ONLY `textAlign`, so the role link is untouched.
|
|
757
|
+
const persistBlockTextAlign = (textAlign: string | undefined) => {
|
|
758
|
+
if (!textAlign) return;
|
|
759
|
+
|
|
760
|
+
const value = { textAlign };
|
|
761
|
+
|
|
765
762
|
if (props.name === 'textItems') {
|
|
766
763
|
contentSettingStore.updateTextItemTextStyleTypeWithStyles({
|
|
767
764
|
id: props.rawId,
|
|
768
765
|
name: props.name,
|
|
769
|
-
value
|
|
770
|
-
...fontStyleChanges,
|
|
771
|
-
fontSize: fontSettings.selectedFontSize,
|
|
772
|
-
},
|
|
766
|
+
value,
|
|
773
767
|
index: props.textItemIndex,
|
|
774
768
|
});
|
|
775
769
|
} else {
|
|
776
770
|
contentSettingStore.updateTextStyles({
|
|
777
771
|
id: props.rawId,
|
|
778
772
|
name: props.name,
|
|
779
|
-
value
|
|
780
|
-
...fontStyleChanges,
|
|
781
|
-
},
|
|
773
|
+
value,
|
|
782
774
|
});
|
|
783
775
|
}
|
|
784
776
|
};
|
|
785
777
|
|
|
778
|
+
// The subset of the block's typography that DIFFERS from its linked role — the promotable
|
|
779
|
+
// override set. Empty when the block matches its role (colour is element-first, excluded).
|
|
780
|
+
const getTypographyOverride = (): Record<string, string> => {
|
|
781
|
+
const role = selectedGlobalTextStyles.value?.style as
|
|
782
|
+
| Record<string, string>
|
|
783
|
+
| undefined;
|
|
784
|
+
|
|
785
|
+
if (!role) return {};
|
|
786
|
+
|
|
787
|
+
const override: Record<string, string> = {};
|
|
788
|
+
|
|
789
|
+
Object.entries(readBlockTypography(editor)).forEach(([key, value]) => {
|
|
790
|
+
// A role-var mark is linked, not an override — the value IS the role.
|
|
791
|
+
if (isRoleVarRef(value)) return;
|
|
792
|
+
|
|
793
|
+
const promoted =
|
|
794
|
+
key === 'textDecoration'
|
|
795
|
+
? composeTextDecoration(role[key], value)
|
|
796
|
+
: value;
|
|
797
|
+
|
|
798
|
+
if (
|
|
799
|
+
typeof promoted === 'string' &&
|
|
800
|
+
normTypographyValue(key, promoted) !==
|
|
801
|
+
normTypographyValue(key, role[key])
|
|
802
|
+
) {
|
|
803
|
+
override[key] = promoted;
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
return override;
|
|
808
|
+
};
|
|
809
|
+
|
|
810
|
+
// Drives the role dropdown's `*` and the "modified style" toggle: true when any run of this
|
|
811
|
+
// linked block differs from its role's typography — one bold word counts.
|
|
812
|
+
const hasTypographyOverride = (): boolean => {
|
|
813
|
+
const role = getRoleStyle() as Record<string, unknown> | undefined;
|
|
814
|
+
|
|
815
|
+
return !!role && hasRunTypographyOverride(editor, role);
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
// A word-level override has no single value to promote, so "Apply changes to all" needs a
|
|
819
|
+
// whole-block one.
|
|
820
|
+
const canApplyTypographyToRole = (): boolean =>
|
|
821
|
+
isCanonicalLinked(props.styles) &&
|
|
822
|
+
Object.keys(getTypographyOverride()).length > 0;
|
|
823
|
+
|
|
824
|
+
// Reset to default: re-link this block's typography to its role (see `relinkTypographyChain`).
|
|
825
|
+
// skipStyleDetection keeps the role link so this doesn't read as a detaching style edit.
|
|
826
|
+
const resetTypographyToRole = () => {
|
|
827
|
+
const role = getRoleStyle() as Record<string, unknown> | undefined;
|
|
828
|
+
|
|
829
|
+
markUserCommand();
|
|
830
|
+
skipStyleDetection(relinkTypographyChain(editor, role)).run();
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
// A role switch resets only typography (ADR-0020): runs relink to the new role, colour stays.
|
|
834
|
+
// An undo/redo restores the doc that went with the role, so it only moves the dropdown tick —
|
|
835
|
+
// the apply bumps `snapshotAppliedToken` in the same tick as it writes the role.
|
|
836
|
+
watch(
|
|
837
|
+
[() => props.styles.textStyleType, () => historyStore.snapshotAppliedToken],
|
|
838
|
+
([newType, token], [oldType, oldToken]) => {
|
|
839
|
+
if (!newType || newType === oldType) return;
|
|
840
|
+
|
|
841
|
+
textStyleTypeOptions.forEach((item) => {
|
|
842
|
+
item.isSelected = item.value === newType;
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
if (token === oldToken) resetTypographyToRole();
|
|
846
|
+
},
|
|
847
|
+
);
|
|
848
|
+
|
|
849
|
+
// Apply to all: promote this block's whole-block typography into the role definition (every
|
|
850
|
+
// block linked to the role adopts it), relink this block's runs that now equal the role —
|
|
851
|
+
// word-level overrides stay, unlike Reset — and re-normalize siblings against the new role.
|
|
852
|
+
// Mirrors the sidebar TextStyleField.saveToGlobal, sourcing the overrides from the RTE marks.
|
|
853
|
+
const applyTypographyToRole = () => {
|
|
854
|
+
const type = props.styles.textStyleType;
|
|
855
|
+
const role = selectedGlobalTextStyles.value?.style;
|
|
856
|
+
const override = getTypographyOverride();
|
|
857
|
+
|
|
858
|
+
if (!type || !role || !Object.keys(override).length) return;
|
|
859
|
+
|
|
860
|
+
const previousRole = { ...role } as unknown as Record<string, unknown>;
|
|
861
|
+
const nextRole = { ...role, ...override } as TextStyleDeclaration;
|
|
862
|
+
|
|
863
|
+
markUserCommand();
|
|
864
|
+
styleSettingsStore.setTextStyleOption({ type, style: nextRole });
|
|
865
|
+
skipStyleDetection(
|
|
866
|
+
relinkRoleEqualRunsChain(
|
|
867
|
+
editor,
|
|
868
|
+
nextRole as unknown as Record<string, unknown>,
|
|
869
|
+
previousRole,
|
|
870
|
+
),
|
|
871
|
+
).run();
|
|
872
|
+
contentSettingStore.renormalizeTextStylesForRole(type, previousRole, {
|
|
873
|
+
id: props.rawId,
|
|
874
|
+
name: props.name,
|
|
875
|
+
index: props.textItemIndex,
|
|
876
|
+
doc: sanitizeRteJson(editor.getJSON()),
|
|
877
|
+
});
|
|
878
|
+
};
|
|
879
|
+
|
|
786
880
|
const onFocus = () => {
|
|
787
881
|
emit('focus');
|
|
788
882
|
};
|
|
@@ -871,6 +965,7 @@ export const useRichTextEditor = (
|
|
|
871
965
|
? { from: selection.from, to: selection.to }
|
|
872
966
|
: undefined;
|
|
873
967
|
|
|
968
|
+
markUserCommand();
|
|
874
969
|
applyHyperlinkToEditor(url, text, selectionRange);
|
|
875
970
|
isHyperlinkPopupOpen.value = false;
|
|
876
971
|
break;
|
|
@@ -883,6 +978,7 @@ export const useRichTextEditor = (
|
|
|
883
978
|
content_type: props.contentType,
|
|
884
979
|
},
|
|
885
980
|
});
|
|
981
|
+
markUserCommand();
|
|
886
982
|
removeHyperlinkFromComposable();
|
|
887
983
|
isHyperlinkPopupOpen.value = false;
|
|
888
984
|
break;
|
|
@@ -912,8 +1008,10 @@ export const useRichTextEditor = (
|
|
|
912
1008
|
lineHeightValue,
|
|
913
1009
|
selectedFont: computed(() => selectedFont.value),
|
|
914
1010
|
setInitialStyleSettings,
|
|
915
|
-
|
|
916
|
-
|
|
1011
|
+
hasTypographyOverride,
|
|
1012
|
+
canApplyTypographyToRole,
|
|
1013
|
+
resetTypographyToRole,
|
|
1014
|
+
applyTypographyToRole,
|
|
917
1015
|
handleHyperlink,
|
|
918
1016
|
hyperlinkValue,
|
|
919
1017
|
setHyperlinkUrlValue,
|