@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
|
@@ -4,12 +4,15 @@ import {
|
|
|
4
4
|
type TextContent,
|
|
5
5
|
type MailingListContent,
|
|
6
6
|
type ContactFormContent,
|
|
7
|
+
type ShopContent,
|
|
7
8
|
type ColorItem,
|
|
9
|
+
type TextStyleDeclaration,
|
|
8
10
|
type HeaderButton,
|
|
9
11
|
} from '../models';
|
|
10
12
|
import {
|
|
11
13
|
BRAND_PAGE_TYPES,
|
|
12
14
|
BUTTON_LINK_TYPE,
|
|
15
|
+
BrandPageModel,
|
|
13
16
|
PageHeaderDesktop,
|
|
14
17
|
PageStyles,
|
|
15
18
|
} from '../models';
|
|
@@ -18,20 +21,29 @@ import {
|
|
|
18
21
|
mapToContactFormViewModel,
|
|
19
22
|
mapToImageViewModel,
|
|
20
23
|
mapToMailingListViewModel,
|
|
24
|
+
mapToPageFooterViewModel,
|
|
21
25
|
mapToPageHeaderViewModel,
|
|
22
26
|
mapToProfileViewModel,
|
|
23
27
|
mapToTextViewModel,
|
|
24
28
|
mapToViewModel,
|
|
29
|
+
applyViewModelTextStyles,
|
|
30
|
+
getBrandPageViewModelFromBrandPageModel,
|
|
31
|
+
getCriticalResourceURLs,
|
|
32
|
+
resolveSaveContactTitleStyle,
|
|
25
33
|
} from './view-model.util';
|
|
26
|
-
import {
|
|
34
|
+
import type { BrandPageViewModel } from '../view-models';
|
|
35
|
+
import {
|
|
36
|
+
ALIGN_CARD_CENTER,
|
|
37
|
+
HEADER_DISPLAY,
|
|
38
|
+
NAVIGATION_DISPLAY,
|
|
39
|
+
} from '../constants';
|
|
27
40
|
import * as uuid from 'uuid';
|
|
28
41
|
import {
|
|
29
42
|
DEFAULT_TEXT_ALIGN,
|
|
30
43
|
FONT_SIZE_BODY,
|
|
31
44
|
FONT_SIZE_HEADINGS,
|
|
32
|
-
FONT_SIZE_PROFILE_NAME,
|
|
33
|
-
LINE_HEIGHT_BODY,
|
|
34
45
|
LINE_HEIGHT_HEADINGS,
|
|
46
|
+
FALLBACK_DEFAULT_LINK_COLOR,
|
|
35
47
|
} from '../constants';
|
|
36
48
|
import { createInitialBannerSectionContent } from '@brand-page-maker/models';
|
|
37
49
|
|
|
@@ -58,6 +70,25 @@ const createOldProfileContent = (): ProfileContent => {
|
|
|
58
70
|
};
|
|
59
71
|
};
|
|
60
72
|
|
|
73
|
+
// BP-5969 (ADR-0020): a section title's own colour lives in its RTE mark, not on the
|
|
74
|
+
// style object. Tests that exercise the "fall back to the title colour" path (the
|
|
75
|
+
// reCAPTCHA disclosure footnote, the social-links icon fill) must put the colour there.
|
|
76
|
+
const rteTitleWithColour = (color: string): unknown => ({
|
|
77
|
+
type: 'doc',
|
|
78
|
+
content: [
|
|
79
|
+
{
|
|
80
|
+
type: 'paragraph',
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: 'text',
|
|
84
|
+
text: 'Title',
|
|
85
|
+
marks: [{ type: 'textStyle', attrs: { color } }],
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
});
|
|
91
|
+
|
|
61
92
|
describe('view model util', () => {
|
|
62
93
|
test('mapToImageViewModel should return image view model when given an image content', () => {
|
|
63
94
|
// Arrange
|
|
@@ -78,43 +109,44 @@ describe('view model util', () => {
|
|
|
78
109
|
expect(viewModel.role).toBe(content.type);
|
|
79
110
|
expect(viewModel.type).toBe('image');
|
|
80
111
|
});
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// Act
|
|
87
|
-
const viewModel = mapToProfileViewModel(profileContent, pageStyles);
|
|
88
|
-
|
|
89
|
-
// Assert
|
|
90
|
-
expect(viewModel.titleStyle?.fontSize).toBe(FONT_SIZE_BODY);
|
|
91
|
-
expect(viewModel.titleStyle?.lineHeight).toBe(LINE_HEIGHT_BODY);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test('mapToProfileViewModel should return profile view model with default name text styles when given an old profile content', () => {
|
|
95
|
-
// Arrange
|
|
96
|
-
const pageStyles = new PageStyles();
|
|
97
|
-
const profileContent = createOldProfileContent();
|
|
98
|
-
|
|
99
|
-
// Act
|
|
100
|
-
const viewModel = mapToProfileViewModel(profileContent, pageStyles);
|
|
101
|
-
|
|
102
|
-
// Assert
|
|
103
|
-
expect(viewModel.nameStyle?.fontSize).toBe(FONT_SIZE_PROFILE_NAME);
|
|
104
|
-
expect(viewModel.nameStyle?.lineHeight).toBe(LINE_HEIGHT_HEADINGS);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test('mapToProfileViewModel should return profile view model with default description text styles when given an old profile content', () => {
|
|
108
|
-
// Arrange
|
|
112
|
+
// BP-5969 (R3 revision) — the profile's built-in size/line-height defaults are deleted
|
|
113
|
+
// outright, on a role or off it: an unset field draws through its role, real or a fallback
|
|
114
|
+
// (T3.1). Old field names ("default title/name/description text styles") retired with them.
|
|
115
|
+
test('profile has no built-in size', () => {
|
|
109
116
|
const pageStyles = new PageStyles();
|
|
110
|
-
const
|
|
117
|
+
const onRoles: ProfileContent = {
|
|
118
|
+
...createOldProfileContent(),
|
|
119
|
+
titleStyle: {
|
|
120
|
+
textAlign: DEFAULT_TEXT_ALIGN,
|
|
121
|
+
textStyleType: 'paragraph2',
|
|
122
|
+
},
|
|
123
|
+
descriptionStyle: {
|
|
124
|
+
textAlign: DEFAULT_TEXT_ALIGN,
|
|
125
|
+
textStyleType: 'paragraph2',
|
|
126
|
+
},
|
|
127
|
+
nameStyle: { textAlign: DEFAULT_TEXT_ALIGN, textStyleType: 'heading5' },
|
|
128
|
+
};
|
|
129
|
+
const noRole = createOldProfileContent();
|
|
111
130
|
|
|
112
|
-
|
|
113
|
-
|
|
131
|
+
for (const profileContent of [onRoles, noRole]) {
|
|
132
|
+
const viewModel = mapToProfileViewModel(profileContent, pageStyles);
|
|
114
133
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
134
|
+
for (const key of [
|
|
135
|
+
'titleStyle',
|
|
136
|
+
'descriptionStyle',
|
|
137
|
+
'nameStyle',
|
|
138
|
+
] as const) {
|
|
139
|
+
const style = viewModel[key] as TextStyleDeclaration;
|
|
140
|
+
|
|
141
|
+
expect(style.fontSize).toBeUndefined();
|
|
142
|
+
expect(style.lineHeight).toBeUndefined();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// The no-role fields still get a canonical fallback role (R3), not a bare `undefined`.
|
|
147
|
+
expect(
|
|
148
|
+
mapToProfileViewModel(noRole, pageStyles).titleStyle?.textStyleType,
|
|
149
|
+
).toBeTruthy();
|
|
118
150
|
});
|
|
119
151
|
|
|
120
152
|
// The profile card echoes the global button style — fill, shadow AND outline — so it
|
|
@@ -233,7 +265,9 @@ describe('view model util', () => {
|
|
|
233
265
|
// element override. `migration-21` strips that field on existing models, which
|
|
234
266
|
// is what keeps published sites rendering identically; this test covers the
|
|
235
267
|
// post-cascade resolver contract, and the migration suite covers the strip.
|
|
236
|
-
|
|
268
|
+
// R1: page data no longer merges the role's typography in, so a fontSize the field never
|
|
269
|
+
// set itself is undefined — the fallback role's CSS var supplies it at render, not this object.
|
|
270
|
+
test('mapToTextViewModel keeps the legacy-role colour cascade; typography stays own-values-only', () => {
|
|
237
271
|
// Arrange
|
|
238
272
|
const pageStyles = new PageStyles();
|
|
239
273
|
|
|
@@ -269,11 +303,15 @@ describe('view model util', () => {
|
|
|
269
303
|
);
|
|
270
304
|
|
|
271
305
|
// Assert — the paragraphs style defines no colour, so this inherits.
|
|
272
|
-
expect(
|
|
273
|
-
|
|
306
|
+
expect(
|
|
307
|
+
(viewModel.textStyle as TextStyleDeclaration)?.color,
|
|
308
|
+
).toBeUndefined();
|
|
309
|
+
expect(
|
|
310
|
+
(viewModel.textStyle as TextStyleDeclaration)?.fontSize,
|
|
311
|
+
).toBeUndefined();
|
|
274
312
|
});
|
|
275
313
|
|
|
276
|
-
test('
|
|
314
|
+
test('does not render an un-migrated legacy textColor sidecar', () => {
|
|
277
315
|
// Arrange
|
|
278
316
|
const pageStyles = new PageStyles();
|
|
279
317
|
|
|
@@ -297,8 +335,11 @@ describe('view model util', () => {
|
|
|
297
335
|
BRAND_PAGE_TYPES.brandSite,
|
|
298
336
|
);
|
|
299
337
|
|
|
300
|
-
//
|
|
301
|
-
|
|
338
|
+
// Migration-22 folds this value into textStyle before rendering. The view model deliberately
|
|
339
|
+
// does not keep a legacy sidecar fallback alive for data that bypasses the migration gate.
|
|
340
|
+
expect(
|
|
341
|
+
(viewModel.textStyle as TextStyleDeclaration)?.color,
|
|
342
|
+
).toBeUndefined();
|
|
302
343
|
});
|
|
303
344
|
|
|
304
345
|
test('Profile text alignment should not overwrite if there is an existing text alignment', () => {
|
|
@@ -345,48 +386,70 @@ describe('view model util', () => {
|
|
|
345
386
|
test("the element's own colour wins over the global text style's", () => {
|
|
346
387
|
const pageStyles = new PageStyles();
|
|
347
388
|
|
|
348
|
-
|
|
389
|
+
(
|
|
390
|
+
pageStyles.textStyles.textStyleOptions.paragraphs
|
|
391
|
+
.style as unknown as Record<string, unknown>
|
|
392
|
+
).color = '#00ff00';
|
|
349
393
|
|
|
350
394
|
const viewModel = mapText(
|
|
351
395
|
textContentWith({
|
|
352
396
|
textStyleType: 'paragraphs',
|
|
353
397
|
color: 'var(--palette-0)',
|
|
354
|
-
}),
|
|
398
|
+
} as TextStyleDeclaration),
|
|
355
399
|
pageStyles,
|
|
356
400
|
);
|
|
357
401
|
|
|
358
|
-
expect(viewModel.textStyle?.color).toBe(
|
|
402
|
+
expect((viewModel.textStyle as TextStyleDeclaration)?.color).toBe(
|
|
403
|
+
'var(--palette-0)',
|
|
404
|
+
);
|
|
359
405
|
});
|
|
360
406
|
|
|
361
|
-
|
|
407
|
+
// R1: colour keeps its own cascade; typography no longer merges the role's values in — a
|
|
408
|
+
// painter references the role for the rest (`roleTypographyStyle`/`fillRteRunTypography`).
|
|
409
|
+
test('colour still cascades from the global text style; typography does not', () => {
|
|
362
410
|
const pageStyles = new PageStyles();
|
|
363
411
|
|
|
364
|
-
|
|
412
|
+
(
|
|
413
|
+
pageStyles.textStyles.textStyleOptions.paragraphs
|
|
414
|
+
.style as unknown as Record<string, unknown>
|
|
415
|
+
).color = '#00ff00';
|
|
365
416
|
pageStyles.textStyles.textStyleOptions.paragraphs.style.fontSize =
|
|
366
417
|
FONT_SIZE_HEADINGS;
|
|
367
418
|
|
|
368
419
|
const viewModel = mapText(
|
|
369
|
-
textContentWith({
|
|
420
|
+
textContentWith({
|
|
421
|
+
textStyleType: 'paragraphs',
|
|
422
|
+
color: '#ff0000',
|
|
423
|
+
} as TextStyleDeclaration),
|
|
370
424
|
pageStyles,
|
|
371
425
|
);
|
|
372
426
|
|
|
373
|
-
expect(viewModel.textStyle?.color).toBe(
|
|
374
|
-
|
|
427
|
+
expect((viewModel.textStyle as TextStyleDeclaration)?.color).toBe(
|
|
428
|
+
'#ff0000',
|
|
429
|
+
);
|
|
430
|
+
expect(
|
|
431
|
+
(viewModel.textStyle as TextStyleDeclaration)?.fontSize,
|
|
432
|
+
).toBeUndefined();
|
|
375
433
|
});
|
|
376
434
|
|
|
377
|
-
//
|
|
378
|
-
//
|
|
379
|
-
test('an element with only a link
|
|
435
|
+
// ADR-0020: a linked element with only the link takes NO colour from its role —
|
|
436
|
+
// it resolves to undefined and renders the page base coat by root inheritance.
|
|
437
|
+
test('an element with only a link takes no colour from its role (undefined → base coat)', () => {
|
|
380
438
|
const pageStyles = new PageStyles();
|
|
381
439
|
|
|
382
|
-
|
|
440
|
+
(
|
|
441
|
+
pageStyles.textStyles.textStyleOptions.paragraphs
|
|
442
|
+
.style as unknown as Record<string, unknown>
|
|
443
|
+
).color = '#00ff00';
|
|
383
444
|
|
|
384
445
|
const viewModel = mapText(
|
|
385
446
|
textContentWith({ textStyleType: 'paragraphs' }),
|
|
386
447
|
pageStyles,
|
|
387
448
|
);
|
|
388
449
|
|
|
389
|
-
expect(
|
|
450
|
+
expect(
|
|
451
|
+
(viewModel.textStyle as TextStyleDeclaration)?.color,
|
|
452
|
+
).toBeUndefined();
|
|
390
453
|
});
|
|
391
454
|
|
|
392
455
|
test('no element colour and no global colour resolves to undefined (the page base coat applies by root CSS inheritance)', () => {
|
|
@@ -400,7 +463,9 @@ describe('view model util', () => {
|
|
|
400
463
|
// Deliberately NOT '#0000ff' — the site-wide default reaches the text by
|
|
401
464
|
// inheritance from the root element, not through the resolver. Seeding it
|
|
402
465
|
// here would read as an element override and beat the global text style.
|
|
403
|
-
expect(
|
|
466
|
+
expect(
|
|
467
|
+
(viewModel.textStyle as TextStyleDeclaration)?.color,
|
|
468
|
+
).toBeUndefined();
|
|
404
469
|
});
|
|
405
470
|
});
|
|
406
471
|
|
|
@@ -413,11 +478,17 @@ describe('view model util', () => {
|
|
|
413
478
|
const mapContent = (content: any, pageStyles: PageStyles): any =>
|
|
414
479
|
mapToViewModel(pageStyles, BRAND_PAGE_TYPES.brandSite, {})(content);
|
|
415
480
|
|
|
416
|
-
test('testimonial
|
|
481
|
+
test('testimonial link-only styles take no colour from their role (role colour retired)', () => {
|
|
417
482
|
const pageStyles = new PageStyles();
|
|
418
483
|
|
|
419
|
-
|
|
420
|
-
|
|
484
|
+
(
|
|
485
|
+
pageStyles.textStyles.textStyleOptions.titles
|
|
486
|
+
.style as unknown as Record<string, unknown>
|
|
487
|
+
).color = '#00ff00';
|
|
488
|
+
(
|
|
489
|
+
pageStyles.textStyles.textStyleOptions.paragraphs
|
|
490
|
+
.style as unknown as Record<string, unknown>
|
|
491
|
+
).color = '#00ff00';
|
|
421
492
|
|
|
422
493
|
const viewModel = mapContent(
|
|
423
494
|
{
|
|
@@ -431,34 +502,113 @@ describe('view model util', () => {
|
|
|
431
502
|
pageStyles,
|
|
432
503
|
);
|
|
433
504
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
expect(viewModel.
|
|
437
|
-
expect(viewModel.
|
|
505
|
+
// ADR-0020: role colour does not cascade — link-only fields resolve to undefined
|
|
506
|
+
// (the mapper still never pre-seeds a default that would beat that).
|
|
507
|
+
expect(viewModel.titleStyle?.color).toBeUndefined();
|
|
508
|
+
expect(viewModel.nameStyle?.color).toBeUndefined();
|
|
509
|
+
expect(viewModel.positionStyle?.color).toBeUndefined();
|
|
510
|
+
expect(viewModel.testimonialStyle?.color).toBeUndefined();
|
|
438
511
|
});
|
|
439
512
|
|
|
440
|
-
test('social-links title
|
|
513
|
+
test('social-links title takes no role colour; the icon fill never follows the title colour', () => {
|
|
441
514
|
const pageStyles = new PageStyles();
|
|
442
515
|
|
|
443
|
-
|
|
444
|
-
|
|
516
|
+
(
|
|
517
|
+
pageStyles.textStyles.textStyleOptions.heading1
|
|
518
|
+
.style as unknown as Record<string, unknown>
|
|
519
|
+
).color = '#00ff00';
|
|
520
|
+
|
|
521
|
+
const socialLinks = (iconFillStyles: BrandPageCssStyle): any =>
|
|
522
|
+
mapContent(
|
|
523
|
+
{
|
|
524
|
+
id: '1',
|
|
525
|
+
type: 'social-links',
|
|
526
|
+
title: rteTitleWithColour('#0000ff'),
|
|
527
|
+
titleStyle: { textStyleType: 'heading1' },
|
|
528
|
+
iconFillStyles,
|
|
529
|
+
socialLinks: [],
|
|
530
|
+
},
|
|
531
|
+
pageStyles,
|
|
532
|
+
);
|
|
533
|
+
|
|
534
|
+
// ADR-0020: heading1's role colour does not cascade → the title takes no colour.
|
|
535
|
+
expect(socialLinks({}).titleStyle?.color).toBeUndefined();
|
|
536
|
+
// The icons paint their stored fill (baked at birth / by migration-22), not the
|
|
537
|
+
// title's mark colour — recolouring the title must not repaint them.
|
|
538
|
+
expect(socialLinks({ fill: '#ff0000' }).iconFillStyles?.fill).toBe(
|
|
539
|
+
'#ff0000',
|
|
540
|
+
);
|
|
541
|
+
expect(socialLinks({}).iconFillStyles?.fill).toBeUndefined();
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
test('shop "no products" label takes the title colour when it has one', () => {
|
|
545
|
+
const pageStyles = new PageStyles();
|
|
445
546
|
|
|
446
547
|
const viewModel = mapContent(
|
|
447
548
|
{
|
|
448
549
|
id: '1',
|
|
449
|
-
type: '
|
|
450
|
-
|
|
451
|
-
|
|
550
|
+
type: 'shop-section',
|
|
551
|
+
title: rteTitleWithColour('#0000ff'),
|
|
552
|
+
description: '',
|
|
553
|
+
successMessage: '',
|
|
554
|
+
products: [],
|
|
555
|
+
displayStyle: 'text',
|
|
556
|
+
aspectRatio: '1:1',
|
|
557
|
+
fillColor: {},
|
|
558
|
+
defaultBorderColor: {},
|
|
559
|
+
itemTextStyle: {},
|
|
560
|
+
backgroundStyle: {},
|
|
561
|
+
shopPaymentConfig: {
|
|
562
|
+
paymentConfig: {},
|
|
563
|
+
paymentOptionDisplayType: 'text',
|
|
564
|
+
paymentOptionImageType: 'none',
|
|
565
|
+
isCustomerRequestDetailsEnabled: false,
|
|
566
|
+
isShippingEnabled: false,
|
|
567
|
+
},
|
|
452
568
|
},
|
|
453
569
|
pageStyles,
|
|
454
570
|
);
|
|
455
571
|
|
|
456
|
-
expect(viewModel.
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
572
|
+
expect(viewModel.noProductsColor).toBe('#0000ff');
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
// A cleared, all-uncoloured or legacy plain-string title has no run colour to read, so
|
|
576
|
+
// the label falls back to the title's own contrast colour — the band's, not the product
|
|
577
|
+
// tile's: a painted tile stacks below the title, not behind it.
|
|
578
|
+
test('shop "no products" label falls back to the title contrast colour when the title has none', () => {
|
|
579
|
+
const pageStyles = new PageStyles();
|
|
580
|
+
|
|
581
|
+
pageStyles.colors = [
|
|
582
|
+
{ id: 'palette-0', value: '#000000', type: 'palette' }, // dark brand
|
|
583
|
+
{ id: 'palette-1', value: '#ffffff', type: 'palette' }, // light brand
|
|
584
|
+
];
|
|
585
|
+
|
|
586
|
+
const shopContent: ShopContent = {
|
|
587
|
+
id: '1',
|
|
588
|
+
type: 'shop-section',
|
|
589
|
+
title: 'Shop',
|
|
590
|
+
description: '',
|
|
591
|
+
successMessage: '',
|
|
592
|
+
products: [],
|
|
593
|
+
displayStyle: 'text',
|
|
594
|
+
aspectRatio: '1:1',
|
|
595
|
+
fillColor: { backgroundColor: 'var(--palette-1)' }, // light tile
|
|
596
|
+
defaultBorderColor: {},
|
|
597
|
+
itemTextStyle: {},
|
|
598
|
+
backgroundStyle: { backgroundColor: 'var(--palette-0)' }, // dark band
|
|
599
|
+
shopPaymentConfig: {
|
|
600
|
+
paymentOptions: [],
|
|
601
|
+
paymentOptionDisplayType: 'text',
|
|
602
|
+
paymentOptionImageType: 'auto',
|
|
603
|
+
isCustomerRequestDetailsEnabled: false,
|
|
604
|
+
isShippingEnabled: false,
|
|
605
|
+
},
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
const viewModel = mapContent(shopContent, pageStyles);
|
|
609
|
+
|
|
610
|
+
// Light on the dark band, not the dark-on-dark a tile-routed fallback would give.
|
|
611
|
+
expect(viewModel.noProductsColor).toBe('var(--palette-1)');
|
|
462
612
|
});
|
|
463
613
|
});
|
|
464
614
|
|
|
@@ -658,6 +808,294 @@ describe('view model util', () => {
|
|
|
658
808
|
},
|
|
659
809
|
);
|
|
660
810
|
});
|
|
811
|
+
|
|
812
|
+
// BP-5969 (R1) — page data keeps only what a field sets itself; the painter references
|
|
813
|
+
// the role for the rest (`roleTypographyStyle`/`fillRteRunTypography`). Colour, alignment,
|
|
814
|
+
// autoscale and `textStyleType` still resolve here; the seven typography keys do not merge.
|
|
815
|
+
describe('page data carries only own typography (R1)', () => {
|
|
816
|
+
const TYPOGRAPHY_KEYS = [
|
|
817
|
+
'fontFamily',
|
|
818
|
+
'fontSize',
|
|
819
|
+
'fontWeight',
|
|
820
|
+
'fontStyle',
|
|
821
|
+
'letterSpacing',
|
|
822
|
+
'lineHeight',
|
|
823
|
+
'textDecoration',
|
|
824
|
+
] as const;
|
|
825
|
+
|
|
826
|
+
test('page data carries only own typography', () => {
|
|
827
|
+
const pageStyles = new PageStyles();
|
|
828
|
+
const content: any = {
|
|
829
|
+
titleStyle: {
|
|
830
|
+
textStyleType: 'heading2',
|
|
831
|
+
textAlign: 'left',
|
|
832
|
+
color: '#112233',
|
|
833
|
+
},
|
|
834
|
+
};
|
|
835
|
+
|
|
836
|
+
const style = applyViewModelTextStyles(content, pageStyles)
|
|
837
|
+
.titleStyle as TextStyleDeclaration;
|
|
838
|
+
|
|
839
|
+
for (const key of TYPOGRAPHY_KEYS) {
|
|
840
|
+
expect(style[key]).toBeUndefined();
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
expect(style.textStyleType).toBe('heading2');
|
|
844
|
+
expect(style.textAlign).toBe('left');
|
|
845
|
+
expect(style.color).toBe('#112233');
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
test('page data keeps one override', () => {
|
|
849
|
+
const pageStyles = new PageStyles();
|
|
850
|
+
const content: any = {
|
|
851
|
+
titleStyle: {
|
|
852
|
+
textStyleType: 'heading2',
|
|
853
|
+
textAlign: 'left',
|
|
854
|
+
fontSize: '3em',
|
|
855
|
+
},
|
|
856
|
+
};
|
|
857
|
+
|
|
858
|
+
const style = applyViewModelTextStyles(content, pageStyles)
|
|
859
|
+
.titleStyle as TextStyleDeclaration;
|
|
860
|
+
const present = TYPOGRAPHY_KEYS.filter((key) => style[key] !== undefined);
|
|
861
|
+
|
|
862
|
+
expect(present).toEqual(['fontSize']);
|
|
863
|
+
expect(style.fontSize).toBe('3em');
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
// T6.3 (R6): an item already saved at fontSize: 1em keeps it — covered by the second item.
|
|
867
|
+
test('text items carry only own typography', () => {
|
|
868
|
+
const pageStyles = new PageStyles();
|
|
869
|
+
const textContent: TextContent = {
|
|
870
|
+
backgroundColor: {},
|
|
871
|
+
iconUrl: '',
|
|
872
|
+
id: '0',
|
|
873
|
+
text: 'Test text',
|
|
874
|
+
textItems: [
|
|
875
|
+
{ id: 'i1', text: 'One', textStyle: { textStyleType: 'paragraph2' } },
|
|
876
|
+
{
|
|
877
|
+
id: 'i2',
|
|
878
|
+
text: 'Two',
|
|
879
|
+
textStyle: { textStyleType: 'paragraph2', fontSize: '1em' },
|
|
880
|
+
},
|
|
881
|
+
],
|
|
882
|
+
textAlignment: {},
|
|
883
|
+
textColor: {},
|
|
884
|
+
textSize: {},
|
|
885
|
+
textStyle: {},
|
|
886
|
+
type: 'text',
|
|
887
|
+
};
|
|
888
|
+
|
|
889
|
+
const items = mapToTextViewModel(
|
|
890
|
+
textContent,
|
|
891
|
+
pageStyles,
|
|
892
|
+
BRAND_PAGE_TYPES.brandSite,
|
|
893
|
+
).textItems as any[];
|
|
894
|
+
|
|
895
|
+
expect(items[0].textStyle.fontSize).toBeUndefined();
|
|
896
|
+
expect(items[0].textStyle.textStyleType).toBe('paragraph2');
|
|
897
|
+
expect(items[1].textStyle.fontSize).toBe('1em');
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
// S6 — an item with no textStyle at all threw (pickTypography/bestFitRole read it with no
|
|
901
|
+
// `?.`); it must fall back the same way an item with an empty textStyle does.
|
|
902
|
+
test('a text item with no textStyle of its own does not throw', () => {
|
|
903
|
+
const pageStyles = new PageStyles();
|
|
904
|
+
const textContent: TextContent = {
|
|
905
|
+
backgroundColor: {},
|
|
906
|
+
iconUrl: '',
|
|
907
|
+
id: '0',
|
|
908
|
+
text: 'Test text',
|
|
909
|
+
textItems: [{ id: 'i1', text: 'One' } as never],
|
|
910
|
+
textAlignment: {},
|
|
911
|
+
textColor: {},
|
|
912
|
+
textSize: {},
|
|
913
|
+
textStyle: {},
|
|
914
|
+
type: 'text',
|
|
915
|
+
};
|
|
916
|
+
|
|
917
|
+
expect(() =>
|
|
918
|
+
mapToTextViewModel(textContent, pageStyles, BRAND_PAGE_TYPES.brandSite),
|
|
919
|
+
).not.toThrow();
|
|
920
|
+
|
|
921
|
+
const items = mapToTextViewModel(
|
|
922
|
+
textContent,
|
|
923
|
+
pageStyles,
|
|
924
|
+
BRAND_PAGE_TYPES.brandSite,
|
|
925
|
+
).textItems as any[];
|
|
926
|
+
|
|
927
|
+
expect(items[0].textStyle.textStyleType).toBe('paragraph1');
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
test('text off the ten draws through its fallback role', () => {
|
|
931
|
+
const pageStyles = new PageStyles();
|
|
932
|
+
|
|
933
|
+
// A section title with no role, sized like a heading — nearest tier by default size.
|
|
934
|
+
const titleContent: any = { titleStyle: { fontSize: '3em' } };
|
|
935
|
+
const titleStyle = applyViewModelTextStyles(titleContent, pageStyles)
|
|
936
|
+
.titleStyle as TextStyleDeclaration;
|
|
937
|
+
|
|
938
|
+
expect(titleStyle.textStyleType).toBe('heading3');
|
|
939
|
+
expect(titleStyle.fontSize).toBe('3em');
|
|
940
|
+
|
|
941
|
+
// A description the same size stays on a paragraph tier: it holds body text.
|
|
942
|
+
const descriptionContent: any = { descriptionStyle: { fontSize: '3em' } };
|
|
943
|
+
|
|
944
|
+
expect(
|
|
945
|
+
(
|
|
946
|
+
applyViewModelTextStyles(descriptionContent, pageStyles)
|
|
947
|
+
.descriptionStyle as TextStyleDeclaration
|
|
948
|
+
).textStyleType,
|
|
949
|
+
).toBe('paragraph1');
|
|
950
|
+
|
|
951
|
+
// A paragraph linked to the retired `paragraphs` role.
|
|
952
|
+
const paraContent: any = { titleStyle: { textStyleType: 'paragraphs' } };
|
|
953
|
+
|
|
954
|
+
expect(
|
|
955
|
+
(
|
|
956
|
+
applyViewModelTextStyles(paraContent, pageStyles)
|
|
957
|
+
.titleStyle as TextStyleDeclaration
|
|
958
|
+
).textStyleType,
|
|
959
|
+
).toBe('paragraph1');
|
|
960
|
+
|
|
961
|
+
// A section button field with no role: every button label starts on Button text.
|
|
962
|
+
const buttonFieldContent: any = { buttonTextStyle: {} };
|
|
963
|
+
|
|
964
|
+
expect(
|
|
965
|
+
(
|
|
966
|
+
applyViewModelTextStyles(buttonFieldContent, pageStyles)
|
|
967
|
+
.buttonTextStyle as TextStyleDeclaration
|
|
968
|
+
).textStyleType,
|
|
969
|
+
).toBe('button');
|
|
970
|
+
|
|
971
|
+
// A text item with no role and no size falls to Paragraph 1.
|
|
972
|
+
const textContent: TextContent = {
|
|
973
|
+
backgroundColor: {},
|
|
974
|
+
iconUrl: '',
|
|
975
|
+
id: '0',
|
|
976
|
+
text: 'Test text',
|
|
977
|
+
textItems: [{ id: 'i1', text: 'One', textStyle: {} }],
|
|
978
|
+
textAlignment: {},
|
|
979
|
+
textColor: {},
|
|
980
|
+
textSize: {},
|
|
981
|
+
textStyle: {},
|
|
982
|
+
type: 'text',
|
|
983
|
+
};
|
|
984
|
+
const items = mapToTextViewModel(
|
|
985
|
+
textContent,
|
|
986
|
+
pageStyles,
|
|
987
|
+
BRAND_PAGE_TYPES.brandSite,
|
|
988
|
+
).textItems as any[];
|
|
989
|
+
|
|
990
|
+
expect(items[0].textStyle.textStyleType).toBe('paragraph1');
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
// S3 — a section's own CTA (banner/booking/images) reuses the SECTION's content type when
|
|
994
|
+
// building its button view model, which `contentFieldReconnectSpec` doesn't recognise as
|
|
995
|
+
// button content; before the fix a heading-sized no-role label landed on a heading tier via
|
|
996
|
+
// `bestFitRole` instead of Button text.
|
|
997
|
+
test('a no-role banner-section button label draws through Button text, not by size', () => {
|
|
998
|
+
const pageStyles = new PageStyles();
|
|
999
|
+
const bannerContent = createInitialBannerSectionContent();
|
|
1000
|
+
|
|
1001
|
+
bannerContent.buttonTextStyle = { fontSize: '2em' };
|
|
1002
|
+
|
|
1003
|
+
const viewModel = mapToBannerSectionViewModel(
|
|
1004
|
+
bannerContent,
|
|
1005
|
+
pageStyles,
|
|
1006
|
+
{},
|
|
1007
|
+
);
|
|
1008
|
+
|
|
1009
|
+
expect(viewModel.buttonViewModel?.titleStyle.textStyleType).toBe(
|
|
1010
|
+
'button',
|
|
1011
|
+
);
|
|
1012
|
+
});
|
|
1013
|
+
});
|
|
1014
|
+
|
|
1015
|
+
// BP-5969 (R3 revision) — the renderer's built-in typography defaults are deleted outright;
|
|
1016
|
+
// a field with no size/weight of its own carries none in page data, on a role or off it.
|
|
1017
|
+
describe('no built-in typography defaults', () => {
|
|
1018
|
+
test('mailing-list title has no built-in bold or size', () => {
|
|
1019
|
+
const pageStyles = new PageStyles();
|
|
1020
|
+
const contentOnRole: MailingListContent = {
|
|
1021
|
+
id: 'ml-1',
|
|
1022
|
+
type: 'mailing-list',
|
|
1023
|
+
title: 'Subscribe',
|
|
1024
|
+
buttonText: 'Go',
|
|
1025
|
+
titleStyle: { textStyleType: 'heading5' } as TextStyleDeclaration,
|
|
1026
|
+
buttonTextStyle: {},
|
|
1027
|
+
};
|
|
1028
|
+
const contentNoRole: MailingListContent = {
|
|
1029
|
+
...contentOnRole,
|
|
1030
|
+
titleStyle: {} as TextStyleDeclaration,
|
|
1031
|
+
};
|
|
1032
|
+
|
|
1033
|
+
for (const content of [contentOnRole, contentNoRole]) {
|
|
1034
|
+
const style = mapToMailingListViewModel(content, pageStyles)
|
|
1035
|
+
.titleStyle as TextStyleDeclaration;
|
|
1036
|
+
|
|
1037
|
+
expect(style.fontWeight).toBeUndefined();
|
|
1038
|
+
expect(style.fontSize).toBeUndefined();
|
|
1039
|
+
}
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
test('support-me title has no built-in bold', () => {
|
|
1043
|
+
const pageStyles = new PageStyles();
|
|
1044
|
+
const mapContent = (content: any): any =>
|
|
1045
|
+
mapToViewModel(pageStyles, BRAND_PAGE_TYPES.brandSite, {})(content);
|
|
1046
|
+
const base = {
|
|
1047
|
+
id: 'sm-1',
|
|
1048
|
+
type: 'support-me',
|
|
1049
|
+
title: 'Support me',
|
|
1050
|
+
description: '',
|
|
1051
|
+
buttonText: 'Donate',
|
|
1052
|
+
successMessage: '',
|
|
1053
|
+
items: [],
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
const onRole = mapContent({
|
|
1057
|
+
...base,
|
|
1058
|
+
titleStyle: { textStyleType: 'heading5' },
|
|
1059
|
+
});
|
|
1060
|
+
const noRole = mapContent({ ...base, titleStyle: {} });
|
|
1061
|
+
|
|
1062
|
+
expect(onRole.titleStyle?.fontWeight).toBeUndefined();
|
|
1063
|
+
expect(noRole.titleStyle?.fontWeight).toBeUndefined();
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1066
|
+
test('text block ignores legacy style siblings', () => {
|
|
1067
|
+
const pageStyles = new PageStyles();
|
|
1068
|
+
const base = (textStyle: TextContent['textStyle']): TextContent => ({
|
|
1069
|
+
backgroundColor: {},
|
|
1070
|
+
iconUrl: '',
|
|
1071
|
+
id: '0',
|
|
1072
|
+
text: 'Test text',
|
|
1073
|
+
textItems: [],
|
|
1074
|
+
textAlignment: { textAlign: 'left' },
|
|
1075
|
+
textColor: { color: '#123456' },
|
|
1076
|
+
textSize: { fontSize: '1.5em', lineHeight: '1.5' },
|
|
1077
|
+
textStyle,
|
|
1078
|
+
type: 'text',
|
|
1079
|
+
});
|
|
1080
|
+
|
|
1081
|
+
for (const textStyle of [{ textStyleType: 'paragraph2' as const }, {}]) {
|
|
1082
|
+
const viewModel = mapToTextViewModel(
|
|
1083
|
+
base(textStyle),
|
|
1084
|
+
pageStyles,
|
|
1085
|
+
BRAND_PAGE_TYPES.brandSite,
|
|
1086
|
+
);
|
|
1087
|
+
const style = viewModel.textStyle as TextStyleDeclaration;
|
|
1088
|
+
|
|
1089
|
+
expect(style.fontSize).toBeUndefined();
|
|
1090
|
+
expect(style.lineHeight).toBeUndefined();
|
|
1091
|
+
expect(style.textAlign).toBe('center');
|
|
1092
|
+
expect(style.color).toBeUndefined();
|
|
1093
|
+
expect(
|
|
1094
|
+
(viewModel as unknown as Record<string, unknown>).textSize,
|
|
1095
|
+
).toBeUndefined();
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
});
|
|
661
1099
|
});
|
|
662
1100
|
|
|
663
1101
|
// The reCAPTCHA footnote colour is a raw colour anchored to the surface it sits on.
|
|
@@ -670,7 +1108,10 @@ describe('reCAPTCHA disclosure colour (view-model layer)', () => {
|
|
|
670
1108
|
type: 'mailing-list',
|
|
671
1109
|
title: 'Subscribe',
|
|
672
1110
|
buttonText: 'Go',
|
|
673
|
-
titleStyle: {
|
|
1111
|
+
titleStyle: {
|
|
1112
|
+
textAlign: DEFAULT_TEXT_ALIGN,
|
|
1113
|
+
color: '#ff0000',
|
|
1114
|
+
} as TextStyleDeclaration,
|
|
674
1115
|
buttonTextStyle: { textAlign: DEFAULT_TEXT_ALIGN },
|
|
675
1116
|
});
|
|
676
1117
|
|
|
@@ -686,7 +1127,7 @@ describe('reCAPTCHA disclosure colour (view-model layer)', () => {
|
|
|
686
1127
|
successMessage: '',
|
|
687
1128
|
fields: [],
|
|
688
1129
|
responseEmail: '',
|
|
689
|
-
titleStyle: { color: '#ff0000' },
|
|
1130
|
+
titleStyle: { color: '#ff0000' } as TextStyleDeclaration,
|
|
690
1131
|
...overrides,
|
|
691
1132
|
});
|
|
692
1133
|
|
|
@@ -707,7 +1148,9 @@ describe('reCAPTCHA disclosure colour (view-model layer)', () => {
|
|
|
707
1148
|
|
|
708
1149
|
expect(vm.disclosureColor).toMatch(/^#/);
|
|
709
1150
|
expect(vm.disclosureColor).not.toContain('var(');
|
|
710
|
-
expect(vm.disclosureColor).not.toBe(
|
|
1151
|
+
expect(vm.disclosureColor).not.toBe(
|
|
1152
|
+
(vm.titleStyle as TextStyleDeclaration)?.color,
|
|
1153
|
+
);
|
|
711
1154
|
});
|
|
712
1155
|
|
|
713
1156
|
test('mailing-list: a raw hex surface fill still yields a muted colour', () => {
|
|
@@ -721,7 +1164,9 @@ describe('reCAPTCHA disclosure colour (view-model layer)', () => {
|
|
|
721
1164
|
);
|
|
722
1165
|
|
|
723
1166
|
expect(vm.disclosureColor).toMatch(/^#/);
|
|
724
|
-
expect(vm.disclosureColor).not.toBe(
|
|
1167
|
+
expect(vm.disclosureColor).not.toBe(
|
|
1168
|
+
(vm.titleStyle as TextStyleDeclaration)?.color,
|
|
1169
|
+
);
|
|
725
1170
|
});
|
|
726
1171
|
|
|
727
1172
|
test('mailing-list: falls back to the title colour when the surface has no fill', () => {
|
|
@@ -730,11 +1175,16 @@ describe('reCAPTCHA disclosure colour (view-model layer)', () => {
|
|
|
730
1175
|
pageStyles.buttonStyles.style = {};
|
|
731
1176
|
|
|
732
1177
|
const vm = mapToMailingListViewModel(
|
|
733
|
-
|
|
1178
|
+
{
|
|
1179
|
+
...createMailingListContent(),
|
|
1180
|
+
title: rteTitleWithColour('#ff0000') as unknown as string,
|
|
1181
|
+
},
|
|
734
1182
|
pageStyles,
|
|
735
1183
|
);
|
|
736
1184
|
|
|
737
|
-
|
|
1185
|
+
// ADR-0020: the title's own colour lives in its RTE mark; with no surface fill the
|
|
1186
|
+
// disclosure falls back to it.
|
|
1187
|
+
expect(vm.disclosureColor).toBe('#ff0000');
|
|
738
1188
|
expect(vm.disclosureColor).toBeDefined();
|
|
739
1189
|
});
|
|
740
1190
|
|
|
@@ -785,7 +1235,9 @@ describe('reCAPTCHA disclosure colour (view-model layer)', () => {
|
|
|
785
1235
|
|
|
786
1236
|
expect(vm.disclosureColor).toMatch(/^#/);
|
|
787
1237
|
expect(vm.disclosureColor).not.toContain('var(');
|
|
788
|
-
expect(vm.disclosureColor).not.toBe(
|
|
1238
|
+
expect(vm.disclosureColor).not.toBe(
|
|
1239
|
+
(vm.titleStyle as TextStyleDeclaration)?.color,
|
|
1240
|
+
);
|
|
789
1241
|
});
|
|
790
1242
|
|
|
791
1243
|
test('contact-form (brand.page): anchors to the card colour when the card has a fill', () => {
|
|
@@ -808,7 +1260,9 @@ describe('reCAPTCHA disclosure colour (view-model layer)', () => {
|
|
|
808
1260
|
// Anchored to the light card, not the dark button fill: a dark muted colour.
|
|
809
1261
|
expect(vm.disclosureColor).toMatch(/^#/);
|
|
810
1262
|
expect(vm.disclosureColor).not.toContain('var(');
|
|
811
|
-
expect(vm.disclosureColor).not.toBe(
|
|
1263
|
+
expect(vm.disclosureColor).not.toBe(
|
|
1264
|
+
(vm.titleStyle as TextStyleDeclaration)?.color,
|
|
1265
|
+
);
|
|
812
1266
|
});
|
|
813
1267
|
|
|
814
1268
|
test('contact-form: a raw hex surface fill (pre-V2) still yields a muted colour', () => {
|
|
@@ -823,7 +1277,9 @@ describe('reCAPTCHA disclosure colour (view-model layer)', () => {
|
|
|
823
1277
|
);
|
|
824
1278
|
|
|
825
1279
|
expect(vm.disclosureColor).toMatch(/^#/);
|
|
826
|
-
expect(vm.disclosureColor).not.toBe(
|
|
1280
|
+
expect(vm.disclosureColor).not.toBe(
|
|
1281
|
+
(vm.titleStyle as TextStyleDeclaration)?.color,
|
|
1282
|
+
);
|
|
827
1283
|
});
|
|
828
1284
|
|
|
829
1285
|
test('contact-form: a blank palette role resolves via role defaults, not the title', () => {
|
|
@@ -840,7 +1296,9 @@ describe('reCAPTCHA disclosure colour (view-model layer)', () => {
|
|
|
840
1296
|
|
|
841
1297
|
expect(vm.disclosureColor).toMatch(/^#/);
|
|
842
1298
|
expect(vm.disclosureColor).not.toContain('var(');
|
|
843
|
-
expect(vm.disclosureColor).not.toBe(
|
|
1299
|
+
expect(vm.disclosureColor).not.toBe(
|
|
1300
|
+
(vm.titleStyle as TextStyleDeclaration)?.color,
|
|
1301
|
+
);
|
|
844
1302
|
});
|
|
845
1303
|
|
|
846
1304
|
test('contact-form (brandSite, card layout): anchors to the card background', () => {
|
|
@@ -862,7 +1320,9 @@ describe('reCAPTCHA disclosure colour (view-model layer)', () => {
|
|
|
862
1320
|
|
|
863
1321
|
expect(vm.disclosureColor).toMatch(/^#/);
|
|
864
1322
|
expect(vm.disclosureColor).not.toContain('var(');
|
|
865
|
-
expect(vm.disclosureColor).not.toBe(
|
|
1323
|
+
expect(vm.disclosureColor).not.toBe(
|
|
1324
|
+
(vm.titleStyle as TextStyleDeclaration)?.color,
|
|
1325
|
+
);
|
|
866
1326
|
});
|
|
867
1327
|
|
|
868
1328
|
test('contact-form (brandSite, no layout): falls back to the title colour', () => {
|
|
@@ -871,12 +1331,17 @@ describe('reCAPTCHA disclosure colour (view-model layer)', () => {
|
|
|
871
1331
|
pageStyles.buttonStyles.style = {};
|
|
872
1332
|
|
|
873
1333
|
const vm = mapToContactFormViewModel(
|
|
874
|
-
|
|
1334
|
+
{
|
|
1335
|
+
...createContactFormContent({ layoutStyle: '' }),
|
|
1336
|
+
title: rteTitleWithColour('#ff0000') as unknown as string,
|
|
1337
|
+
},
|
|
875
1338
|
pageStyles,
|
|
876
1339
|
BRAND_PAGE_TYPES.brandSite,
|
|
877
1340
|
);
|
|
878
1341
|
|
|
879
|
-
|
|
1342
|
+
// ADR-0020: the title's own colour lives in its RTE mark; with no surface fill the
|
|
1343
|
+
// disclosure falls back to it.
|
|
1344
|
+
expect(vm.disclosureColor).toBe('#ff0000');
|
|
880
1345
|
expect(vm.disclosureColor).toBeDefined();
|
|
881
1346
|
});
|
|
882
1347
|
});
|
|
@@ -901,10 +1366,26 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
901
1366
|
color: BUTTON_TEXT,
|
|
902
1367
|
};
|
|
903
1368
|
// Distinct global text-style colours so a fallback to the page is detectable.
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
1369
|
+
(
|
|
1370
|
+
pageStyles.textStyles.textStyleOptions.headings
|
|
1371
|
+
.style as unknown as Record<string, unknown>
|
|
1372
|
+
).color = '#00ff00';
|
|
1373
|
+
(
|
|
1374
|
+
pageStyles.textStyles.textStyleOptions.paragraphs
|
|
1375
|
+
.style as unknown as Record<string, unknown>
|
|
1376
|
+
).color = '#00ff00';
|
|
1377
|
+
(
|
|
1378
|
+
pageStyles.textStyles.textStyleOptions.titles.style as unknown as Record<
|
|
1379
|
+
string,
|
|
1380
|
+
unknown
|
|
1381
|
+
>
|
|
1382
|
+
).color = '#00ff00';
|
|
1383
|
+
(
|
|
1384
|
+
pageStyles.textStyles.textStyleOptions.buttons.style as unknown as Record<
|
|
1385
|
+
string,
|
|
1386
|
+
unknown
|
|
1387
|
+
>
|
|
1388
|
+
).color = '#0000ff';
|
|
908
1389
|
|
|
909
1390
|
return pageStyles;
|
|
910
1391
|
};
|
|
@@ -929,8 +1410,8 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
929
1410
|
stylesWithButton(),
|
|
930
1411
|
);
|
|
931
1412
|
|
|
932
|
-
expect(vm.titleStyle?.color).toBe(BUTTON_TEXT);
|
|
933
|
-
expect(vm.titleStyle?.color).toContain('var(');
|
|
1413
|
+
expect((vm.titleStyle as TextStyleDeclaration)?.color).toBe(BUTTON_TEXT);
|
|
1414
|
+
expect((vm.titleStyle as TextStyleDeclaration)?.color).toContain('var(');
|
|
934
1415
|
});
|
|
935
1416
|
|
|
936
1417
|
test('mailing-list: title on a neutral-light card follows its global heading colour, not the button text (BP-5886)', () => {
|
|
@@ -948,9 +1429,10 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
948
1429
|
stylesWithButton(),
|
|
949
1430
|
);
|
|
950
1431
|
|
|
951
|
-
// Card ≠ button fill → the button-text default does not apply
|
|
952
|
-
// the
|
|
953
|
-
|
|
1432
|
+
// Card ≠ button fill → the button-text default does not apply. ADR-0020: the role's
|
|
1433
|
+
// colour no longer cascades, so the title resolves to undefined and takes the page
|
|
1434
|
+
// base coat (the generalised contrast bake — Phase 2 — will colour non-default surfaces).
|
|
1435
|
+
expect((vm.titleStyle as TextStyleDeclaration)?.color).toBeUndefined();
|
|
954
1436
|
});
|
|
955
1437
|
|
|
956
1438
|
test('mailing-list: an explicit title colour still wins over the container default', () => {
|
|
@@ -960,16 +1442,19 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
960
1442
|
type: 'mailing-list',
|
|
961
1443
|
title: 'Subscribe',
|
|
962
1444
|
buttonText: 'Go',
|
|
963
|
-
titleStyle: {
|
|
1445
|
+
titleStyle: {
|
|
1446
|
+
textStyleType: 'headings',
|
|
1447
|
+
color: '#abcabc',
|
|
1448
|
+
} as TextStyleDeclaration,
|
|
964
1449
|
backgroundStyle: { backgroundColor: BUTTON_FILL },
|
|
965
1450
|
} as MailingListContent,
|
|
966
1451
|
stylesWithButton(),
|
|
967
1452
|
);
|
|
968
1453
|
|
|
969
|
-
expect(vm.titleStyle?.color).toBe('#abcabc');
|
|
1454
|
+
expect((vm.titleStyle as TextStyleDeclaration)?.color).toBe('#abcabc');
|
|
970
1455
|
});
|
|
971
1456
|
|
|
972
|
-
test('mailing-list: no visible container
|
|
1457
|
+
test('mailing-list: no visible container and no role colour resolves to undefined (base coat)', () => {
|
|
973
1458
|
const pageStyles = stylesWithButton();
|
|
974
1459
|
|
|
975
1460
|
pageStyles.buttonStyles.style = {}; // no own container and no button fill
|
|
@@ -985,7 +1470,8 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
985
1470
|
pageStyles,
|
|
986
1471
|
);
|
|
987
1472
|
|
|
988
|
-
|
|
1473
|
+
// ADR-0020: no container default and the role colour retired → undefined (base coat).
|
|
1474
|
+
expect((vm.titleStyle as TextStyleDeclaration)?.color).toBeUndefined();
|
|
989
1475
|
});
|
|
990
1476
|
|
|
991
1477
|
test('mailing-list: with no own container it contrasts the global button fill', () => {
|
|
@@ -1000,10 +1486,10 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
1000
1486
|
stylesWithButton(),
|
|
1001
1487
|
);
|
|
1002
1488
|
|
|
1003
|
-
expect(vm.titleStyle?.color).toBe(BUTTON_TEXT);
|
|
1489
|
+
expect((vm.titleStyle as TextStyleDeclaration)?.color).toBe(BUTTON_TEXT);
|
|
1004
1490
|
});
|
|
1005
1491
|
|
|
1006
|
-
test('request-payment: title/description/item text take the container default; a set item textColor still wins', () => {
|
|
1492
|
+
test('request-payment: title/description/success message/item text take the container default; a set item textColor still wins', () => {
|
|
1007
1493
|
const vm = mapContent(
|
|
1008
1494
|
{
|
|
1009
1495
|
id: 'rp-1',
|
|
@@ -1011,6 +1497,7 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
1011
1497
|
title: 'Pay',
|
|
1012
1498
|
titleStyle: { textStyleType: 'paragraphs' },
|
|
1013
1499
|
descriptionStyle: { textStyleType: 'paragraphs' },
|
|
1500
|
+
successMessageStyle: { textStyleType: 'paragraphs' },
|
|
1014
1501
|
itemTextStyle: { textStyleType: 'paragraphs' },
|
|
1015
1502
|
textColor: { color: '#abcabc' },
|
|
1016
1503
|
backgroundStyle: { backgroundColor: BUTTON_FILL },
|
|
@@ -1019,13 +1506,18 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
1019
1506
|
stylesWithButton(),
|
|
1020
1507
|
);
|
|
1021
1508
|
|
|
1022
|
-
expect(vm.titleStyle?.color).toBe(BUTTON_TEXT);
|
|
1023
|
-
expect(vm.descriptionStyle?.color).toBe(
|
|
1509
|
+
expect((vm.titleStyle as TextStyleDeclaration)?.color).toBe(BUTTON_TEXT);
|
|
1510
|
+
expect((vm.descriptionStyle as TextStyleDeclaration)?.color).toBe(
|
|
1511
|
+
BUTTON_TEXT,
|
|
1512
|
+
);
|
|
1513
|
+
expect((vm.successMessageStyle as TextStyleDeclaration)?.color).toBe(
|
|
1514
|
+
BUTTON_TEXT,
|
|
1515
|
+
);
|
|
1024
1516
|
// itemTextStyle merges content.textColor first, so its explicit colour wins.
|
|
1025
|
-
expect(vm.itemTextStyle?.color).toBe('#abcabc');
|
|
1517
|
+
expect((vm.itemTextStyle as TextStyleDeclaration)?.color).toBe('#abcabc');
|
|
1026
1518
|
});
|
|
1027
1519
|
|
|
1028
|
-
test('support-me: title/heading/description/item take the container default; button text stays on the buttons global', () => {
|
|
1520
|
+
test('support-me: title/heading/description/success message/item take the container default; button text stays on the buttons global', () => {
|
|
1029
1521
|
const vm = mapContent(
|
|
1030
1522
|
{
|
|
1031
1523
|
id: 'sm-1',
|
|
@@ -1035,6 +1527,7 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
1035
1527
|
titleStyle: { textStyleType: 'headings' },
|
|
1036
1528
|
headingStyle: { textStyleType: 'paragraphs' },
|
|
1037
1529
|
descriptionStyle: { textStyleType: 'paragraphs' },
|
|
1530
|
+
successMessageStyle: { textStyleType: 'paragraphs' },
|
|
1038
1531
|
itemTextStyle: { textStyleType: 'paragraphs' },
|
|
1039
1532
|
buttonTextStyle: { textStyleType: 'buttons' },
|
|
1040
1533
|
backgroundStyle: { backgroundColor: BUTTON_FILL },
|
|
@@ -1042,12 +1535,18 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
1042
1535
|
stylesWithButton(),
|
|
1043
1536
|
);
|
|
1044
1537
|
|
|
1045
|
-
expect(vm.titleStyle?.color).toBe(BUTTON_TEXT);
|
|
1046
|
-
expect(vm.headingStyle?.color).toBe(BUTTON_TEXT);
|
|
1047
|
-
expect(vm.descriptionStyle?.color).toBe(
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
expect(vm.
|
|
1538
|
+
expect((vm.titleStyle as TextStyleDeclaration)?.color).toBe(BUTTON_TEXT);
|
|
1539
|
+
expect((vm.headingStyle as TextStyleDeclaration)?.color).toBe(BUTTON_TEXT);
|
|
1540
|
+
expect((vm.descriptionStyle as TextStyleDeclaration)?.color).toBe(
|
|
1541
|
+
BUTTON_TEXT,
|
|
1542
|
+
);
|
|
1543
|
+
expect((vm.successMessageStyle as TextStyleDeclaration)?.color).toBe(
|
|
1544
|
+
BUTTON_TEXT,
|
|
1545
|
+
);
|
|
1546
|
+
expect((vm.itemTextStyle as TextStyleDeclaration)?.color).toBe(BUTTON_TEXT);
|
|
1547
|
+
// buttonTextStyle is NOT container-bound and ADR-0020 retires the role colour →
|
|
1548
|
+
// it resolves to undefined (the page base coat).
|
|
1549
|
+
expect((vm.buttonTextStyle as TextStyleDeclaration)?.color).toBeUndefined();
|
|
1051
1550
|
});
|
|
1052
1551
|
|
|
1053
1552
|
test('contact-form (brand.page): title/description/success message take the container default', () => {
|
|
@@ -1072,13 +1571,18 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
1072
1571
|
BRAND_PAGE_TYPES.default,
|
|
1073
1572
|
);
|
|
1074
1573
|
|
|
1075
|
-
expect(vm.titleStyle?.color).toBe(BUTTON_TEXT);
|
|
1076
|
-
expect(vm.descriptionStyle?.color).toBe(
|
|
1077
|
-
|
|
1078
|
-
|
|
1574
|
+
expect((vm.titleStyle as TextStyleDeclaration)?.color).toBe(BUTTON_TEXT);
|
|
1575
|
+
expect((vm.descriptionStyle as TextStyleDeclaration)?.color).toBe(
|
|
1576
|
+
BUTTON_TEXT,
|
|
1577
|
+
);
|
|
1578
|
+
expect((vm.successMessageStyle as TextStyleDeclaration)?.color).toBe(
|
|
1579
|
+
BUTTON_TEXT,
|
|
1580
|
+
);
|
|
1581
|
+
// ADR-0020: buttonTextStyle (not container-bound) takes no role colour → undefined.
|
|
1582
|
+
expect((vm.buttonTextStyle as TextStyleDeclaration)?.color).toBeUndefined();
|
|
1079
1583
|
});
|
|
1080
1584
|
|
|
1081
|
-
test('contact-form (brandSite): container default
|
|
1585
|
+
test('contact-form (brandSite): container default out of scope; link-only fields resolve to undefined (role colour retired)', () => {
|
|
1082
1586
|
const vm = mapToContactFormViewModel(
|
|
1083
1587
|
{
|
|
1084
1588
|
id: 'cf-1',
|
|
@@ -1099,10 +1603,13 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
1099
1603
|
BRAND_PAGE_TYPES.brandSite,
|
|
1100
1604
|
);
|
|
1101
1605
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
//
|
|
1105
|
-
|
|
1606
|
+
// ADR-0020: role colour retired → link-only fields resolve to undefined (base coat).
|
|
1607
|
+
expect((vm.titleStyle as TextStyleDeclaration)?.color).toBeUndefined();
|
|
1608
|
+
// successMessageStyle resolves (it was skipped before); on brandSite the container
|
|
1609
|
+
// default is out of scope and the role colour no longer cascades → undefined.
|
|
1610
|
+
expect(
|
|
1611
|
+
(vm.successMessageStyle as TextStyleDeclaration)?.color,
|
|
1612
|
+
).toBeUndefined();
|
|
1106
1613
|
});
|
|
1107
1614
|
|
|
1108
1615
|
test('regression: a content type with no container-bound keys is unaffected by the container default', () => {
|
|
@@ -1116,8 +1623,9 @@ describe('container-aware text colour defaults (view-model layer)', () => {
|
|
|
1116
1623
|
stylesWithButton(),
|
|
1117
1624
|
);
|
|
1118
1625
|
|
|
1119
|
-
|
|
1120
|
-
expect(vm.
|
|
1626
|
+
// ADR-0020: role colour retired → link-only fields resolve to undefined (base coat).
|
|
1627
|
+
expect((vm.titleStyle as TextStyleDeclaration)?.color).toBeUndefined();
|
|
1628
|
+
expect(vm.nameStyle?.color).toBeUndefined();
|
|
1121
1629
|
});
|
|
1122
1630
|
});
|
|
1123
1631
|
|
|
@@ -1230,7 +1738,10 @@ describe('mapToPageHeaderViewModel header button', () => {
|
|
|
1230
1738
|
);
|
|
1231
1739
|
});
|
|
1232
1740
|
|
|
1233
|
-
|
|
1741
|
+
// R1: page data carries only the label's own typography; the retired `buttons` role's
|
|
1742
|
+
// font family isn't copied in — the fixed successor role (`button`) supplies it at render,
|
|
1743
|
+
// through the CSS var the role class references, not this object.
|
|
1744
|
+
test('resolves the button role, not a copied font family, against the site text styles', () => {
|
|
1234
1745
|
const styles = new PageStyles();
|
|
1235
1746
|
|
|
1236
1747
|
styles.textStyles.textStyleOptions.buttons.style.fontFamily = 'Lato';
|
|
@@ -1241,16 +1752,16 @@ describe('mapToPageHeaderViewModel header button', () => {
|
|
|
1241
1752
|
[],
|
|
1242
1753
|
).headerButtonViewModel;
|
|
1243
1754
|
|
|
1244
|
-
expect(vm?.titleStyle?.fontFamily).
|
|
1755
|
+
expect(vm?.titleStyle?.fontFamily).toBeUndefined();
|
|
1756
|
+
expect(vm?.titleStyle?.textStyleType).toBe('button');
|
|
1245
1757
|
});
|
|
1246
1758
|
|
|
1247
1759
|
// The maker writes buttonTextStyle only once the author touches the style field,
|
|
1248
|
-
// so an untouched button still has to inherit the site's button
|
|
1249
|
-
|
|
1760
|
+
// so an untouched button still has to inherit the site's button role — its role, not a
|
|
1761
|
+
// copied value (R1).
|
|
1762
|
+
test('defaults to the site button role when none is authored', () => {
|
|
1250
1763
|
const styles = new PageStyles();
|
|
1251
1764
|
|
|
1252
|
-
styles.textStyles.textStyleOptions.buttons.style.fontFamily = 'Lato';
|
|
1253
|
-
|
|
1254
1765
|
const vm = mapToPageHeaderViewModel(
|
|
1255
1766
|
new PageHeaderDesktop({
|
|
1256
1767
|
headerButton: { ...headerButton, buttonTextStyle: undefined },
|
|
@@ -1259,8 +1770,318 @@ describe('mapToPageHeaderViewModel header button', () => {
|
|
|
1259
1770
|
[],
|
|
1260
1771
|
).headerButtonViewModel;
|
|
1261
1772
|
|
|
1262
|
-
expect(vm?.titleStyle?.textStyleType).toBe('
|
|
1263
|
-
expect(vm?.titleStyle?.fontFamily).
|
|
1773
|
+
expect(vm?.titleStyle?.textStyleType).toBe('button');
|
|
1774
|
+
expect(vm?.titleStyle?.fontFamily).toBeUndefined();
|
|
1775
|
+
});
|
|
1776
|
+
|
|
1777
|
+
test('a header button carries no role font family in page data; its own override holds', () => {
|
|
1778
|
+
const styles = new PageStyles();
|
|
1779
|
+
const mapWith = (buttonTextStyle: TextStyleDeclaration) =>
|
|
1780
|
+
mapToPageHeaderViewModel(
|
|
1781
|
+
new PageHeaderDesktop({
|
|
1782
|
+
headerButton: { ...headerButton, buttonTextStyle },
|
|
1783
|
+
}),
|
|
1784
|
+
styles,
|
|
1785
|
+
[],
|
|
1786
|
+
).headerButtonViewModel;
|
|
1787
|
+
|
|
1788
|
+
styles.textStyles.textStyleOptions.button.style.fontFamily = 'Oswald';
|
|
1789
|
+
|
|
1790
|
+
// R1: a role edit repaints the label at render, through the CSS var the role class
|
|
1791
|
+
// supplies — page data itself never carries the role's font family.
|
|
1792
|
+
expect(
|
|
1793
|
+
mapWith({ textStyleType: 'button' })?.titleStyle?.fontFamily,
|
|
1794
|
+
).toBeUndefined();
|
|
1795
|
+
expect(
|
|
1796
|
+
mapWith({ textStyleType: 'button', fontFamily: 'Lora' })?.titleStyle
|
|
1797
|
+
?.fontFamily,
|
|
1798
|
+
).toBe('Lora');
|
|
1799
|
+
});
|
|
1800
|
+
|
|
1801
|
+
// R3: no built-in line-height default — on a role or off it, an unset label carries no
|
|
1802
|
+
// line height in page data; it follows the role (real, or the button fallback) at render.
|
|
1803
|
+
describe('label line height', () => {
|
|
1804
|
+
const mapWith = (
|
|
1805
|
+
buttonTextStyle: HeaderButton['buttonTextStyle'],
|
|
1806
|
+
styles = new PageStyles(),
|
|
1807
|
+
) =>
|
|
1808
|
+
mapToPageHeaderViewModel(
|
|
1809
|
+
new PageHeaderDesktop({
|
|
1810
|
+
headerButton: { ...headerButton, buttonTextStyle },
|
|
1811
|
+
}),
|
|
1812
|
+
styles,
|
|
1813
|
+
[],
|
|
1814
|
+
).headerButtonViewModel?.titleStyle;
|
|
1815
|
+
|
|
1816
|
+
test.each(['button', 'heading1'] as const)(
|
|
1817
|
+
'an unset label on %s carries no line height in page data',
|
|
1818
|
+
(textStyleType) => {
|
|
1819
|
+
const styles = new PageStyles();
|
|
1820
|
+
|
|
1821
|
+
styles.textStyles.textStyleOptions[textStyleType].style.lineHeight =
|
|
1822
|
+
'1.15';
|
|
1823
|
+
|
|
1824
|
+
expect(
|
|
1825
|
+
mapWith({ textStyleType }, styles)?.lineHeight,
|
|
1826
|
+
).toBeUndefined();
|
|
1827
|
+
},
|
|
1828
|
+
);
|
|
1829
|
+
|
|
1830
|
+
test('the label own line height beats the role', () => {
|
|
1831
|
+
expect(
|
|
1832
|
+
mapWith({ textStyleType: 'heading1', lineHeight: '1.5' })?.lineHeight,
|
|
1833
|
+
).toBe('1.5');
|
|
1834
|
+
});
|
|
1835
|
+
|
|
1836
|
+
test('an unset label on no role has no built-in default; it falls back to Button text', () => {
|
|
1837
|
+
const titleStyle = mapWith({ textAlign: 'center' });
|
|
1838
|
+
|
|
1839
|
+
expect(titleStyle?.lineHeight).toBeUndefined();
|
|
1840
|
+
expect(titleStyle?.textStyleType).toBe('button');
|
|
1841
|
+
});
|
|
1264
1842
|
});
|
|
1265
1843
|
});
|
|
1266
1844
|
});
|
|
1845
|
+
|
|
1846
|
+
describe('save contact button text style', () => {
|
|
1847
|
+
test('with no field of its own, the Save Contact label carries no typography — only the Button text role', () => {
|
|
1848
|
+
const styles = new PageStyles();
|
|
1849
|
+
|
|
1850
|
+
const resolved = resolveSaveContactTitleStyle(undefined, styles.textStyles);
|
|
1851
|
+
|
|
1852
|
+
expect(resolved.textStyleType).toBe('button');
|
|
1853
|
+
expect(resolved.fontFamily).toBeUndefined();
|
|
1854
|
+
expect(resolved.fontSize).toBeUndefined();
|
|
1855
|
+
});
|
|
1856
|
+
|
|
1857
|
+
test('the label always resolves to the Button text role, including when the field names the retired Buttons role', () => {
|
|
1858
|
+
const styles = new PageStyles();
|
|
1859
|
+
|
|
1860
|
+
expect(
|
|
1861
|
+
resolveSaveContactTitleStyle(
|
|
1862
|
+
{ textStyleType: 'button' },
|
|
1863
|
+
styles.textStyles,
|
|
1864
|
+
).textStyleType,
|
|
1865
|
+
).toBe('button');
|
|
1866
|
+
expect(
|
|
1867
|
+
resolveSaveContactTitleStyle(
|
|
1868
|
+
{ textStyleType: 'buttons' as never },
|
|
1869
|
+
styles.textStyles,
|
|
1870
|
+
).textStyleType,
|
|
1871
|
+
).toBe('button');
|
|
1872
|
+
});
|
|
1873
|
+
|
|
1874
|
+
// S8 — the field naming a DIFFERENT canonical role (not just the retired `buttons`) must
|
|
1875
|
+
// still normalise to Button text; Save Contact never draws through any other role.
|
|
1876
|
+
test('a stray canonical role on the field is still normalised to Button text', () => {
|
|
1877
|
+
const styles = new PageStyles();
|
|
1878
|
+
|
|
1879
|
+
expect(
|
|
1880
|
+
resolveSaveContactTitleStyle(
|
|
1881
|
+
{ textStyleType: 'heading2' as never },
|
|
1882
|
+
styles.textStyles,
|
|
1883
|
+
).textStyleType,
|
|
1884
|
+
).toBe('button');
|
|
1885
|
+
});
|
|
1886
|
+
|
|
1887
|
+
test('a save contact override holds; a Button text role edit is not copied in', () => {
|
|
1888
|
+
const styles = new PageStyles();
|
|
1889
|
+
|
|
1890
|
+
styles.textStyles.textStyleOptions.button.style.fontFamily = 'Oswald';
|
|
1891
|
+
|
|
1892
|
+
const resolved = resolveSaveContactTitleStyle(
|
|
1893
|
+
{ textStyleType: 'button', fontSize: '1.25em', lineHeight: '1.5' },
|
|
1894
|
+
styles.textStyles,
|
|
1895
|
+
);
|
|
1896
|
+
|
|
1897
|
+
expect(resolved.fontSize).toBe('1.25em');
|
|
1898
|
+
expect(resolved.lineHeight).toBe('1.5');
|
|
1899
|
+
expect(resolved.fontFamily).toBeUndefined();
|
|
1900
|
+
expect(resolved.textStyleType).toBe('button');
|
|
1901
|
+
});
|
|
1902
|
+
|
|
1903
|
+
test('the page view model passes the save contact buttonTextStyle through', () => {
|
|
1904
|
+
const buttonTextStyle: TextStyleDeclaration = {
|
|
1905
|
+
textStyleType: 'button',
|
|
1906
|
+
fontSize: '1.25em',
|
|
1907
|
+
};
|
|
1908
|
+
const model = new BrandPageModel({
|
|
1909
|
+
brandPageType: BRAND_PAGE_TYPES.brandContact,
|
|
1910
|
+
saveContactSettings: {
|
|
1911
|
+
isSavingEnabled: true,
|
|
1912
|
+
hideBranding: false,
|
|
1913
|
+
buttonTextStyle,
|
|
1914
|
+
},
|
|
1915
|
+
});
|
|
1916
|
+
|
|
1917
|
+
const viewModel = getBrandPageViewModelFromBrandPageModel(
|
|
1918
|
+
model,
|
|
1919
|
+
undefined,
|
|
1920
|
+
true,
|
|
1921
|
+
{} as Parameters<typeof getBrandPageViewModelFromBrandPageModel>[3],
|
|
1922
|
+
);
|
|
1923
|
+
|
|
1924
|
+
expect(viewModel.saveContactSettings?.buttonTextStyle).toEqual(
|
|
1925
|
+
buttonTextStyle,
|
|
1926
|
+
);
|
|
1927
|
+
});
|
|
1928
|
+
});
|
|
1929
|
+
|
|
1930
|
+
// Header and footer text is rebuilt through the model constructors on every load, so the
|
|
1931
|
+
// render is checked after a round trip through `new BrandPageModel`, the way the published
|
|
1932
|
+
// page and the maker both load a saved site.
|
|
1933
|
+
describe('header and footer text follow their role after a reload', () => {
|
|
1934
|
+
const load = (
|
|
1935
|
+
navStyle: TextStyleDeclaration,
|
|
1936
|
+
hamburgerStyle: TextStyleDeclaration,
|
|
1937
|
+
copyrightStyle: TextStyleDeclaration = {
|
|
1938
|
+
textStyleType: 'paragraph1',
|
|
1939
|
+
textAlign: 'center',
|
|
1940
|
+
},
|
|
1941
|
+
) => {
|
|
1942
|
+
const model = new BrandPageModel({
|
|
1943
|
+
pageHeaderDesktop: {
|
|
1944
|
+
displayStyle: HEADER_DISPLAY.DESKTOP_TAB_5,
|
|
1945
|
+
navigation: {
|
|
1946
|
+
displayType: NAVIGATION_DISPLAY.TAB_1,
|
|
1947
|
+
defaultButtonStyle: navStyle,
|
|
1948
|
+
hamburgerMenuStyle: { defaultButtonStyle: hamburgerStyle },
|
|
1949
|
+
},
|
|
1950
|
+
},
|
|
1951
|
+
pageFooterDesktop: {
|
|
1952
|
+
copyrightText: '© Acme',
|
|
1953
|
+
copyrightStyle,
|
|
1954
|
+
},
|
|
1955
|
+
} as never);
|
|
1956
|
+
|
|
1957
|
+
const styles = new PageStyles();
|
|
1958
|
+
const roles = styles.textStyles.textStyleOptions;
|
|
1959
|
+
|
|
1960
|
+
roles.paragraph1.style = {
|
|
1961
|
+
...roles.paragraph1.style,
|
|
1962
|
+
fontFamily: 'Anton',
|
|
1963
|
+
fontSize: '1.5em',
|
|
1964
|
+
fontWeight: 'bold',
|
|
1965
|
+
};
|
|
1966
|
+
roles.button.style = { ...roles.button.style, fontFamily: 'Oswald' };
|
|
1967
|
+
|
|
1968
|
+
return {
|
|
1969
|
+
header: mapToPageHeaderViewModel(model.pageHeaderDesktop, styles, []),
|
|
1970
|
+
footer: mapToPageFooterViewModel(model.pageFooterDesktop, styles),
|
|
1971
|
+
};
|
|
1972
|
+
};
|
|
1973
|
+
|
|
1974
|
+
test('a linked nav tab and hamburger keep their role and carry no role typography', () => {
|
|
1975
|
+
const { header } = load(
|
|
1976
|
+
{ textStyleType: 'paragraph1' },
|
|
1977
|
+
{ textStyleType: 'button' },
|
|
1978
|
+
);
|
|
1979
|
+
|
|
1980
|
+
expect(header.navigation.defaultButtonStyle.textStyleType).toBe(
|
|
1981
|
+
'paragraph1',
|
|
1982
|
+
);
|
|
1983
|
+
expect(header.navigation.defaultButtonStyle.fontFamily).toBeUndefined();
|
|
1984
|
+
expect(header.navigation.defaultButtonStyle.fontSize).toBeUndefined();
|
|
1985
|
+
expect(
|
|
1986
|
+
header.navigation.hamburgerMenuStyle.defaultButtonStyle.textStyleType,
|
|
1987
|
+
).toBe('button');
|
|
1988
|
+
expect(
|
|
1989
|
+
header.navigation.hamburgerMenuStyle.defaultButtonStyle.fontFamily,
|
|
1990
|
+
).toBeUndefined();
|
|
1991
|
+
});
|
|
1992
|
+
|
|
1993
|
+
test('a linked nav tab keeps its own override and no role typography for the rest', () => {
|
|
1994
|
+
const { header } = load(
|
|
1995
|
+
{ textStyleType: 'paragraph1', fontSize: '1em' },
|
|
1996
|
+
{ textStyleType: 'button' },
|
|
1997
|
+
);
|
|
1998
|
+
|
|
1999
|
+
expect(header.navigation.defaultButtonStyle).toMatchObject({
|
|
2000
|
+
textStyleType: 'paragraph1',
|
|
2001
|
+
fontSize: '1em',
|
|
2002
|
+
});
|
|
2003
|
+
expect(header.navigation.defaultButtonStyle.fontFamily).toBeUndefined();
|
|
2004
|
+
});
|
|
2005
|
+
|
|
2006
|
+
test('a linked nav tab keeps a fallback link colour when its own is cleared', () => {
|
|
2007
|
+
const { header } = load(
|
|
2008
|
+
{ textStyleType: 'paragraph1', color: '' },
|
|
2009
|
+
{ textStyleType: 'button' },
|
|
2010
|
+
);
|
|
2011
|
+
|
|
2012
|
+
expect(header.navigation.defaultButtonStyle.color).toBe(
|
|
2013
|
+
FALLBACK_DEFAULT_LINK_COLOR,
|
|
2014
|
+
);
|
|
2015
|
+
});
|
|
2016
|
+
|
|
2017
|
+
// S3 — nav tabs and the hamburger take an explicit starting role now (matching what the
|
|
2018
|
+
// upgrade assigns them), not `bestFitRole` — so the model's own default size no longer needs
|
|
2019
|
+
// clearing to see the true no-role fallback; it stays as an override either way.
|
|
2020
|
+
test('a tab on no role draws through Paragraph 1 regardless of its own size; a hamburger on no role draws through Button text', () => {
|
|
2021
|
+
const { header } = load({}, {});
|
|
2022
|
+
|
|
2023
|
+
expect(header.navigation.defaultButtonStyle.textStyleType).toBe(
|
|
2024
|
+
'paragraph1',
|
|
2025
|
+
);
|
|
2026
|
+
expect(header.navigation.defaultButtonStyle.fontSize).toBe(FONT_SIZE_BODY);
|
|
2027
|
+
expect(
|
|
2028
|
+
header.navigation.hamburgerMenuStyle.defaultButtonStyle.textStyleType,
|
|
2029
|
+
).toBe('button');
|
|
2030
|
+
});
|
|
2031
|
+
|
|
2032
|
+
test('the footer copyright takes its role', () => {
|
|
2033
|
+
const { footer } = load(
|
|
2034
|
+
{ textStyleType: 'paragraph1' },
|
|
2035
|
+
{ textStyleType: 'button' },
|
|
2036
|
+
{ textStyleType: 'paragraph2', textAlign: 'center', color: '#111111' },
|
|
2037
|
+
);
|
|
2038
|
+
|
|
2039
|
+
expect(footer.copyrightStyle).toMatchObject({
|
|
2040
|
+
textStyleType: 'paragraph2',
|
|
2041
|
+
textAlign: 'center',
|
|
2042
|
+
color: '#111111',
|
|
2043
|
+
overflowWrap: 'anywhere',
|
|
2044
|
+
wordBreak: 'normal',
|
|
2045
|
+
});
|
|
2046
|
+
expect(footer.copyrightStyle.fontFamily).toBeUndefined();
|
|
2047
|
+
expect(footer.copyrightStyle.fontSize).toBeUndefined();
|
|
2048
|
+
|
|
2049
|
+
const { footer: noRoleFooter } = load(
|
|
2050
|
+
{ textStyleType: 'paragraph1' },
|
|
2051
|
+
{ textStyleType: 'button' },
|
|
2052
|
+
{},
|
|
2053
|
+
);
|
|
2054
|
+
|
|
2055
|
+
expect(noRoleFooter.copyrightStyle.textStyleType).toBe('paragraph1');
|
|
2056
|
+
});
|
|
2057
|
+
});
|
|
2058
|
+
|
|
2059
|
+
describe('getCriticalResourceURLs', () => {
|
|
2060
|
+
const SHAPE_URL = 'https://cdn.example.com/shape.svg';
|
|
2061
|
+
|
|
2062
|
+
const viewModelWith = (
|
|
2063
|
+
textStyles: Record<string, unknown>,
|
|
2064
|
+
): BrandPageViewModel =>
|
|
2065
|
+
({
|
|
2066
|
+
styles: {
|
|
2067
|
+
textStyles,
|
|
2068
|
+
backgroundStylesViewModel: { backgroundImageUrl: SHAPE_URL },
|
|
2069
|
+
},
|
|
2070
|
+
}) as unknown as BrandPageViewModel;
|
|
2071
|
+
|
|
2072
|
+
// The renderer layout already preloads every font (0036-retire-text-font-family.md).
|
|
2073
|
+
test.each([
|
|
2074
|
+
['a stale font key', { textFontFamily: 'quattrocentoSans' }],
|
|
2075
|
+
['a stale display name', { textFontFamily: 'Anton SC' }],
|
|
2076
|
+
['no site text font', {}],
|
|
2077
|
+
])(
|
|
2078
|
+
'preloads the background shape and no font, given %s',
|
|
2079
|
+
(_label, textStyles) => {
|
|
2080
|
+
expect(getCriticalResourceURLs(viewModelWith(textStyles))).toEqual({
|
|
2081
|
+
images: [],
|
|
2082
|
+
fonts: [],
|
|
2083
|
+
shapes: [SHAPE_URL],
|
|
2084
|
+
});
|
|
2085
|
+
},
|
|
2086
|
+
);
|
|
2087
|
+
});
|