@designcrowd/library.brand-page 6.2.2 → 6.2.3-ast-faq
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-7P2gNr-R.js → CreatedOnBrandCrowd-de-de-BRisMzFY.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-Dl7BymW6.js → CreatedOnBrandCrowd-en-us-CDDsL9GX.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-CO4FvWVw.js → CreatedOnBrandCrowd-es-es-BkZrEo4j.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-DHNqakQu.js → CreatedOnBrandCrowd-fr-ca-sx_ury7R.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-DHNqakQu.js → CreatedOnBrandCrowd-fr-fr-sx_ury7R.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-CGUC-ZbP.js → CreatedOnBrandCrowd-pt-br-DCWiAfkU.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-CGUC-ZbP.js → CreatedOnBrandCrowd-pt-pt-DCWiAfkU.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-Dvds-Vmy.js → CreatedOnDcom-de-de-C1S7f22L.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-fd3C-8Tp.js → CreatedOnDcom-en-us-DgTlWaXE.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-DTXZW35-.js → CreatedOnDcom-es-es-CxSQJe_V.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-DRCYOKPs.js → CreatedOnDcom-fr-ca-Bbam2tt6.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-DpIB8x2x.js → CreatedOnDcom-fr-fr-Cb0XDRPL.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-Esnxy8wX.js → CreatedOnDcom-pt-br-BjdX3-E3.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-CaiVHFXR.js → CreatedOnDcom-pt-pt-BXpbfopB.js} +1 -1
- package/lib/src/brand-page/constants/misc.constants.d.ts +8 -0
- package/lib/src/brand-page/constants/misc.constants.js +7 -0
- package/lib/src/brand-page/constants/styles.constants.d.ts +2 -0
- package/lib/src/brand-page/constants/styles.constants.js +2 -0
- package/lib/src/brand-page/models/brand-page-context.model.d.ts +0 -2
- package/lib/src/brand-page/models/brand-page-context.model.js +0 -12
- package/lib/src/brand-page/models/content.model.d.ts +1 -0
- package/lib/src/brand-page/models/content.model.js +1 -0
- package/lib/src/brand-page/models/index.d.ts +19 -0
- package/lib/src/brand-page/utils/content-callback-util.d.ts +2 -1
- package/lib/src/brand-page/utils/content-callback-util.js +3 -0
- package/lib/src/brand-page/utils/model.util.d.ts +2 -1
- package/lib/src/brand-page/utils/model.util.js +3 -0
- package/lib/src/brand-page/utils/view-model.util.d.ts +2 -0
- package/lib/src/brand-page/utils/view-model.util.js +24 -0
- package/lib/src/brand-page/view-models.d.ts +9 -2
- package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +0 -1
- package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.js +0 -9
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +10 -42
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +10 -42
- package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +0 -14
- package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +0 -42
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +0 -42
- package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +0 -42
- package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +0 -42
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +0 -42
- package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +0 -42
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +13 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +64 -30
- package/lib/src/brand-page-maker/constants/config-settings-constant.d.ts +2 -1
- package/lib/src/brand-page-maker/constants/config-settings-constant.js +101 -2
- package/lib/src/brand-page-maker/convertors/faq-display-style.convertor.d.ts +3 -0
- package/lib/src/brand-page-maker/convertors/faq-display-style.convertor.js +47 -0
- package/lib/src/brand-page-maker/models/content-settings-configs.d.ts +22 -1
- package/lib/src/brand-page-maker/models/content-settings-configs.js +1 -0
- package/lib/src/brand-page-maker/models/content-settings.d.ts +4 -1
- package/lib/src/brand-page-maker/models/content-settings.js +45 -1
- package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +0 -42
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +1 -0
- package/lib/src/brand-page-maker/utils/apply-color-strategy.js +47 -17
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +6 -0
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +24 -1
- package/lib/src/brand-page-maker/validators/field.validator.js +2 -0
- package/lib/src/bundled-translations-DY9YvuL-.js +179 -0
- package/lib/src/bundles/bundled-translations.json +20 -2
- 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 +143 -36
- package/lib/src/css/library.brand-page-brandPage.min.css +143 -36
- package/lib/src/css/library.brand-page-designCom.min.css +143 -36
- package/lib/src/css/library.brand-page-preview.min.css +143 -36
- package/lib/src/index.mjs +159 -158
- package/lib/src/{lib-V7aqfuiB.js → lib-DwpSAbLZ.js} +26889 -26178
- package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +1 -1
- package/lib/src/shared/color-strategies/color-strategies.js +4 -0
- package/lib/src/shared/color-strategies/rte-field-pairs.d.ts +12 -0
- package/lib/src/shared/color-strategies/rte-field-pairs.js +10 -0
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +10 -0
- package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +11 -1
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +10 -0
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +10 -0
- package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +10 -0
- package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.d.ts +14 -1
- package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.js +11 -1
- package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +0 -42
- package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +12 -0
- package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.js +5 -0
- package/lib/src/shared/content-settings/models.d.ts +6 -0
- package/lib/src/shared/content-settings/store/content-settings-store.d.ts +14 -1
- package/lib/src/shared/content-settings/store/content-settings-store.js +24 -2
- package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +0 -42
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +10 -42
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +10 -42
- package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +0 -56
- package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +0 -42
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +0 -42
- package/package.json +2 -2
- package/src/brand-page/components/faq-section/FaqSection.test.ts +292 -0
- package/src/brand-page/components/faq-section/FaqSection.vue +299 -0
- package/src/brand-page/components/page/PageComponent.vue +2 -0
- package/src/brand-page/components/section-heading/SectionHeading.vue +52 -0
- package/src/brand-page/components/text-wrapper/TextWrapper.test.ts +33 -0
- package/src/brand-page/constants/misc.constants.ts +12 -0
- package/src/brand-page/constants/styles.constants.ts +2 -0
- package/src/brand-page/models/brand-page-context.model.ts +0 -23
- package/src/brand-page/models/content.model.ts +1 -0
- package/src/brand-page/models/index.ts +21 -0
- package/src/brand-page/utils/content-callback-util.ts +5 -0
- package/src/brand-page/utils/model.util.ts +7 -0
- package/src/brand-page/utils/view-model.util.test.ts +96 -0
- package/src/brand-page/utils/view-model.util.ts +49 -0
- package/src/brand-page/view-models.ts +12 -1
- package/src/brand-page-maker/components/action-bar/ActionBar.mixin.ts +0 -10
- package/src/brand-page-maker/components/action-bar/ActionBarNavigation.test.ts +8 -49
- package/src/brand-page-maker/components/action-bar/ActionBarNavigation.vue +1 -1
- package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.test.ts +165 -0
- package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +37 -49
- package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +87 -30
- package/src/brand-page-maker/constants/config-settings-constant.ts +108 -0
- package/src/brand-page-maker/constants/faq-section-config.test.ts +151 -0
- package/src/brand-page-maker/convertors/faq-display-style.convertor.ts +59 -0
- package/src/brand-page-maker/convertors/i18n/converter.json +4 -1
- package/src/brand-page-maker/models/content-settings-configs.ts +24 -0
- package/src/brand-page-maker/models/content-settings.ts +57 -0
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +2 -0
- package/src/brand-page-maker/utils/__snapshots__/apply-color-strategy.golden.test.ts.snap +4063 -895
- package/src/brand-page-maker/utils/apply-color-strategy.test.ts +104 -2
- package/src/brand-page-maker/utils/apply-color-strategy.ts +77 -19
- package/src/brand-page-maker/utils/rich-text-editor.util.test.ts +110 -0
- package/src/brand-page-maker/utils/rich-text-editor.util.ts +66 -0
- package/src/brand-page-maker/validators/field.validator.ts +2 -0
- package/src/bundles/bundled-translations.json +20 -2
- package/src/composables/useTranslate.ts +2 -1
- package/src/metadata-builder/builders/item-id-utils.test.ts +24 -0
- package/src/metadata-builder/parsers/section-tool-arguments.ts +2 -1
- package/src/metadata-builder/parsers/section-tool-map.test.ts +12 -0
- package/src/shared/color-strategies/color-strategies.ts +4 -0
- package/src/shared/color-strategies/rte-field-pairs.ts +23 -0
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.json +17 -1
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.vue +3 -0
- package/src/shared/content-settings/components/items-field/ItemsField.mixin.ts +11 -1
- package/src/shared/content-settings/components/items-field/ItemsField.vue +8 -2
- package/src/shared/content-settings/components/list-items-field/ListItemsField.test.ts +429 -0
- package/src/shared/content-settings/components/list-items-field/ListItemsField.vue +262 -0
- package/src/shared/content-settings/components/textarea-field/TextareaField.mixin.ts +6 -0
- package/src/shared/content-settings/components/textarea-field/TextareaField.vue +1 -0
- package/src/shared/content-settings/models.ts +7 -0
- package/src/shared/content-settings/store/content-settings-store.test.ts +70 -0
- package/src/shared/content-settings/store/content-settings-store.ts +37 -3
- package/src/shared/ecommerce-settings/util/refreshDuplicatedMetadata.test.ts +19 -0
- package/src/shared/page-settings/store/page-settings-store.test.ts +0 -71
- package/src/utils/minify-brand-page-metadata.test.ts +35 -0
- package/lib/src/bundled-translations-BYUfWBT3.js +0 -179
|
@@ -394,7 +394,11 @@ import {
|
|
|
394
394
|
} from '@designcrowd/fe-shared-lib';
|
|
395
395
|
import { EditorContent } from '@tiptap/vue-3';
|
|
396
396
|
import { BubbleMenu } from '@tiptap/vue-3/menus';
|
|
397
|
-
import {
|
|
397
|
+
import {
|
|
398
|
+
useRichTextEditor,
|
|
399
|
+
writeListItemStyles,
|
|
400
|
+
} from '../../composables/rich-text-editor/useRichTextEditor';
|
|
401
|
+
import type { RteItemStyleTarget } from '@shared/content-settings/models';
|
|
398
402
|
import FontPicker from '@shared/font-family-selector/FontPicker.vue';
|
|
399
403
|
import ColorField from '@shared/content-settings/components/color-field/ColorField.vue';
|
|
400
404
|
import UrlField from '@shared/content-settings/components/url-field/UrlField.vue';
|
|
@@ -460,6 +464,8 @@ const props = withDefaults(
|
|
|
460
464
|
textItemIndex: number;
|
|
461
465
|
item: TextItem;
|
|
462
466
|
contentType: string;
|
|
467
|
+
/** Edit a list item's text: toolbar styles go to that item's own style field. */
|
|
468
|
+
itemStyleTarget?: RteItemStyleTarget;
|
|
463
469
|
}>(),
|
|
464
470
|
{
|
|
465
471
|
id: '',
|
|
@@ -472,6 +478,7 @@ const props = withDefaults(
|
|
|
472
478
|
textStyleName: '',
|
|
473
479
|
styles: () => ({}),
|
|
474
480
|
rawId: '',
|
|
481
|
+
itemStyleTarget: undefined,
|
|
475
482
|
},
|
|
476
483
|
);
|
|
477
484
|
|
|
@@ -602,6 +609,29 @@ const isAddLinkButtonDisabled = computed(() => {
|
|
|
602
609
|
);
|
|
603
610
|
});
|
|
604
611
|
|
|
612
|
+
// Where this editor's role/colour writes land: the list item it edits, a Text block
|
|
613
|
+
// item, or the section's own `${name}Style`.
|
|
614
|
+
const writeStyles = (value: TextStyleDeclaration): void => {
|
|
615
|
+
if (writeListItemStyles(contentSettingStore, props, value)) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (props.name === 'textItems') {
|
|
620
|
+
contentSettingStore.updateTextItemTextStyleTypeWithStyles({
|
|
621
|
+
id: props.rawId,
|
|
622
|
+
name: props.name,
|
|
623
|
+
value,
|
|
624
|
+
index: props.textItemIndex,
|
|
625
|
+
});
|
|
626
|
+
} else {
|
|
627
|
+
contentSettingStore.updateTextStyles({
|
|
628
|
+
id: props.rawId,
|
|
629
|
+
name: props.name,
|
|
630
|
+
value,
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
|
|
605
635
|
// Keeps a text ITEM's own style in step with the global text style it links to.
|
|
606
636
|
watch(
|
|
607
637
|
() =>
|
|
@@ -641,20 +671,7 @@ watch(
|
|
|
641
671
|
backgroundColor: undefined,
|
|
642
672
|
};
|
|
643
673
|
|
|
644
|
-
|
|
645
|
-
contentSettingStore.updateTextItemTextStyleTypeWithStyles({
|
|
646
|
-
id: props.rawId,
|
|
647
|
-
name: props.name,
|
|
648
|
-
value,
|
|
649
|
-
index: props.textItemIndex,
|
|
650
|
-
});
|
|
651
|
-
} else {
|
|
652
|
-
contentSettingStore.updateTextStyles({
|
|
653
|
-
id: props.rawId,
|
|
654
|
-
name: props.name,
|
|
655
|
-
value,
|
|
656
|
-
});
|
|
657
|
-
}
|
|
674
|
+
writeStyles(value);
|
|
658
675
|
}
|
|
659
676
|
} else {
|
|
660
677
|
// make sure text style options are updated and selected Global style is set to none
|
|
@@ -685,26 +702,10 @@ const onSelectTextStyleType = (option: ButtonGroupOption) => {
|
|
|
685
702
|
if (optionSelected) {
|
|
686
703
|
selectedGlobalTextStyles.value = item.value;
|
|
687
704
|
if (option.value === undefined) {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
value: {
|
|
693
|
-
textStyleType: undefined,
|
|
694
|
-
fontSize: fontSettings.selectedFontSize,
|
|
695
|
-
},
|
|
696
|
-
index: props.textItemIndex,
|
|
697
|
-
});
|
|
698
|
-
} else {
|
|
699
|
-
contentSettingStore.updateTextStyles({
|
|
700
|
-
id: props.rawId,
|
|
701
|
-
name: props.name,
|
|
702
|
-
value: {
|
|
703
|
-
textStyleType: undefined,
|
|
704
|
-
fontSize: fontSettings.selectedFontSize,
|
|
705
|
-
},
|
|
706
|
-
});
|
|
707
|
-
}
|
|
705
|
+
writeStyles({
|
|
706
|
+
textStyleType: undefined,
|
|
707
|
+
fontSize: fontSettings.selectedFontSize,
|
|
708
|
+
});
|
|
708
709
|
} else {
|
|
709
710
|
const selectedStyle: BrandPageCssStyle =
|
|
710
711
|
styleSettingsStore.textStyles.textStyleOptions[
|
|
@@ -723,20 +724,7 @@ const onSelectTextStyleType = (option: ButtonGroupOption) => {
|
|
|
723
724
|
backgroundColor: undefined,
|
|
724
725
|
};
|
|
725
726
|
|
|
726
|
-
|
|
727
|
-
contentSettingStore.updateTextItemTextStyleTypeWithStyles({
|
|
728
|
-
id: props.rawId,
|
|
729
|
-
name: props.name,
|
|
730
|
-
value,
|
|
731
|
-
index: props.textItemIndex,
|
|
732
|
-
});
|
|
733
|
-
} else {
|
|
734
|
-
contentSettingStore.updateTextStyles({
|
|
735
|
-
id: props.rawId,
|
|
736
|
-
name: props.name,
|
|
737
|
-
value,
|
|
738
|
-
});
|
|
739
|
-
}
|
|
727
|
+
writeStyles(value);
|
|
740
728
|
}
|
|
741
729
|
item.isSelected = true;
|
|
742
730
|
} else {
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
import type { ButtonGroupOption } from '@brand-page-maker/models/button-group.model';
|
|
33
33
|
import { letterSpacingValueConvertor } from '@brand-page-maker/convertors';
|
|
34
34
|
import { useUiContentSettingsStore } from '@shared/content-settings/store';
|
|
35
|
+
import type { RteItemStyleTarget } from '@shared/content-settings/models';
|
|
35
36
|
import { useHistoryStore } from '@brand-page-maker/stores/history/history-store';
|
|
36
37
|
import { AllSelection } from 'prosemirror-state';
|
|
37
38
|
import { useHyperlink } from './hyperlink';
|
|
@@ -113,6 +114,32 @@ export const useExternalRichTextEditor = (): {
|
|
|
113
114
|
};
|
|
114
115
|
};
|
|
115
116
|
|
|
117
|
+
/**
|
|
118
|
+
* An editor bound to a list item (`itemStyleTarget`) writes its toolbar styles to that
|
|
119
|
+
* item's own style field instead of the section-level `${name}Style`. Returns false when
|
|
120
|
+
* the editor has no item target, so the caller falls through to its section-level write.
|
|
121
|
+
*/
|
|
122
|
+
export const writeListItemStyles = (
|
|
123
|
+
store: ReturnType<typeof useUiContentSettingsStore>,
|
|
124
|
+
props: { rawId: string; name: string; itemStyleTarget?: RteItemStyleTarget },
|
|
125
|
+
value: TextStyleDeclaration,
|
|
126
|
+
isHydrationWrite?: boolean,
|
|
127
|
+
): boolean => {
|
|
128
|
+
if (!props.itemStyleTarget) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
store.updateListItemTextStyles({
|
|
133
|
+
id: props.rawId,
|
|
134
|
+
name: props.name,
|
|
135
|
+
value,
|
|
136
|
+
target: props.itemStyleTarget,
|
|
137
|
+
isHydrationWrite,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return true;
|
|
141
|
+
};
|
|
142
|
+
|
|
116
143
|
export const useRichTextEditor = (
|
|
117
144
|
model: ModelRef<any>,
|
|
118
145
|
props: {
|
|
@@ -126,6 +153,7 @@ export const useRichTextEditor = (
|
|
|
126
153
|
textItemIndex: number;
|
|
127
154
|
item: TextItem;
|
|
128
155
|
contentType: string;
|
|
156
|
+
itemStyleTarget?: RteItemStyleTarget;
|
|
129
157
|
},
|
|
130
158
|
emit: (event: 'focus' | 'blur' | 'update:modelValue', ...args: any[]) => void,
|
|
131
159
|
fontSettings: {
|
|
@@ -426,6 +454,23 @@ export const useRichTextEditor = (
|
|
|
426
454
|
}
|
|
427
455
|
});
|
|
428
456
|
|
|
457
|
+
// Set while a toolbar command runs. The toolbar has taken focus by then, so
|
|
458
|
+
// `isFocused` alone would tag the command's write as hydration and fold it into
|
|
459
|
+
// the previous undo entry — hidden only when a style write rides along and opens
|
|
460
|
+
// an entry of its own. Synchronous commands only: the spacing sliders dispatch
|
|
461
|
+
// after a debounce and are not covered.
|
|
462
|
+
let isRunningToolbarCommand = false;
|
|
463
|
+
|
|
464
|
+
const runAsToolbarCommand = <T>(command: () => T): T => {
|
|
465
|
+
isRunningToolbarCommand = true;
|
|
466
|
+
|
|
467
|
+
try {
|
|
468
|
+
return command();
|
|
469
|
+
} finally {
|
|
470
|
+
isRunningToolbarCommand = false;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
|
|
429
474
|
// Update model when editor content changes. RTE content is stored as Tiptap
|
|
430
475
|
// JSON (BP-5787). getJSON() is already in hand (the editor holds the doc) and
|
|
431
476
|
// is sanitised natively — no getHTML(), no DOMPurify, no extra editor — so
|
|
@@ -439,15 +484,9 @@ export const useRichTextEditor = (
|
|
|
439
484
|
// field → store chain and arms the history merge at the moment of the
|
|
440
485
|
// store write — arming here at emit time would lapse before the
|
|
441
486
|
// debounce fires. Genuine edits happen while focused and commit
|
|
442
|
-
// normally.
|
|
443
|
-
//
|
|
444
|
-
// Known limitation: a programmatic toolbar command run on an editor the
|
|
445
|
-
// user hasn't focused yet would also merge (losing that undo step). Today
|
|
446
|
-
// the RTE only mounts inside an already-open settings drawer and the user
|
|
447
|
-
// focuses it before formatting, so this doesn't occur — revisit if a
|
|
448
|
-
// consumer ever drives toolbar actions on an unfocused editor.
|
|
487
|
+
// normally, and so do synchronous toolbar commands (isRunningToolbarCommand).
|
|
449
488
|
emit('update:modelValue', sanitizeRteJson(editor.getJSON()), {
|
|
450
|
-
isHydrationWrite: !editor.isFocused,
|
|
489
|
+
isHydrationWrite: !editor.isFocused && !isRunningToolbarCommand,
|
|
451
490
|
});
|
|
452
491
|
});
|
|
453
492
|
|
|
@@ -551,26 +590,38 @@ export const useRichTextEditor = (
|
|
|
551
590
|
// write lands ~100ms BEFORE the editor's canonical text write-back, and
|
|
552
591
|
// an unflagged write here would open a plain capture burst that
|
|
553
592
|
// swallows the flagged text write into a phantom entry (BP-5810).
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
593
|
+
const syncedStyles = {
|
|
594
|
+
fontSize: globalStyles.fontSize,
|
|
595
|
+
fontFamily: globalStyles.fontFamily,
|
|
596
|
+
fontWeight: globalStyles.fontWeight,
|
|
597
|
+
fontStyle: globalStyles.fontStyle,
|
|
598
|
+
textDecoration: globalStyles.textDecoration,
|
|
599
|
+
// Keep an element colour override (a creation-time contrast bake, or a
|
|
600
|
+
// colour picked while linked) — only fall back to the global style's colour
|
|
601
|
+
// when the element has none, mirroring `resolveTextColor`'s element-first
|
|
602
|
+
// cascade. Blindly taking `globalStyles.color` here re-derived the linked
|
|
603
|
+
// colour on every RTE mount and clobbered the override.
|
|
604
|
+
color: props.styles?.color || globalStyles.color,
|
|
605
|
+
lineHeight: globalStyles.lineHeight,
|
|
606
|
+
letterSpacing: globalStyles.letterSpacing,
|
|
607
|
+
};
|
|
608
|
+
const isHydrationWrite = !editor.isFocused;
|
|
609
|
+
|
|
610
|
+
if (
|
|
611
|
+
!writeListItemStyles(
|
|
612
|
+
contentSettingStore,
|
|
613
|
+
props,
|
|
614
|
+
syncedStyles,
|
|
615
|
+
isHydrationWrite,
|
|
616
|
+
)
|
|
617
|
+
) {
|
|
618
|
+
contentSettingStore.updateTextStyles({
|
|
619
|
+
id: props.rawId,
|
|
620
|
+
name: props.name,
|
|
621
|
+
value: syncedStyles,
|
|
622
|
+
isHydrationWrite,
|
|
623
|
+
});
|
|
624
|
+
}
|
|
574
625
|
|
|
575
626
|
// sync toolbar editor styles
|
|
576
627
|
fontSettings.selectedFont = globalStyles?.fontFamily ?? 'Lato';
|
|
@@ -762,6 +813,10 @@ export const useRichTextEditor = (
|
|
|
762
813
|
};
|
|
763
814
|
|
|
764
815
|
const syncContentSettings = (fontStyleChanges: TextStyleDeclaration) => {
|
|
816
|
+
if (writeListItemStyles(contentSettingStore, props, fontStyleChanges)) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
|
|
765
820
|
if (props.name === 'textItems') {
|
|
766
821
|
contentSettingStore.updateTextItemTextStyleTypeWithStyles({
|
|
767
822
|
id: props.rawId,
|
|
@@ -897,7 +952,8 @@ export const useRichTextEditor = (
|
|
|
897
952
|
editor,
|
|
898
953
|
onFocus,
|
|
899
954
|
onBlur,
|
|
900
|
-
triggerEditorStyleChange
|
|
955
|
+
triggerEditorStyleChange: (editorOption: EditorOptionType) =>
|
|
956
|
+
runAsToolbarCommand(() => triggerEditorStyleChange(editorOption)),
|
|
901
957
|
toggleBold,
|
|
902
958
|
toggleItalic,
|
|
903
959
|
toggleUnderline,
|
|
@@ -914,7 +970,8 @@ export const useRichTextEditor = (
|
|
|
914
970
|
setInitialStyleSettings,
|
|
915
971
|
copyGlobalStyleSettings,
|
|
916
972
|
unsetAllMarks,
|
|
917
|
-
handleHyperlink
|
|
973
|
+
handleHyperlink: (...args: Parameters<typeof handleHyperlink>) =>
|
|
974
|
+
runAsToolbarCommand(() => handleHyperlink(...args)),
|
|
918
975
|
hyperlinkValue,
|
|
919
976
|
setHyperlinkUrlValue,
|
|
920
977
|
shouldShow,
|
|
@@ -35,8 +35,11 @@ import type {
|
|
|
35
35
|
Content,
|
|
36
36
|
ShopContent,
|
|
37
37
|
BookingSectionContent,
|
|
38
|
+
FaqSectionContent,
|
|
38
39
|
} from '@brand-page';
|
|
39
40
|
import {
|
|
41
|
+
FAQ_DISPLAY_STYLES,
|
|
42
|
+
FAQ_MAX_ITEMS,
|
|
40
43
|
SOCIAL_LINKS_ICON_DISPLAY_STYLES,
|
|
41
44
|
BRAND_PAGE_TYPES,
|
|
42
45
|
DIVIDER_STYLES,
|
|
@@ -84,6 +87,9 @@ import {
|
|
|
84
87
|
VARIANT_DISPLAY_MODES,
|
|
85
88
|
createInitialShopContent,
|
|
86
89
|
createInitialBookingSectionContent,
|
|
90
|
+
createInitialFaqSectionContent,
|
|
91
|
+
createInitialFaqQuestionStyle,
|
|
92
|
+
createInitialFaqAnswerStyle,
|
|
87
93
|
} from '../models';
|
|
88
94
|
import * as uuid from 'uuid';
|
|
89
95
|
import type {
|
|
@@ -149,6 +155,7 @@ import {
|
|
|
149
155
|
import { socialLinksIconDisplayStyleConvertor } from '../convertors/social-links-icon-display-style.convertor';
|
|
150
156
|
import { getTextMediaOptionsConverterByMediaType } from '../convertors/text-image-display-style.convertor';
|
|
151
157
|
import { testimonialDisplayStyleConvertor } from '../convertors/testimonial-display-style-convertor';
|
|
158
|
+
import { faqDisplayStyleConvertor } from '../convertors/faq-display-style.convertor';
|
|
152
159
|
import { pageValidator, urlValidator } from '../validators';
|
|
153
160
|
import { imagesSectionAspectRatioVisibilityAssessor } from '../assessors/images-section-aspect-ratio-visibility.assessor';
|
|
154
161
|
import {
|
|
@@ -3295,6 +3302,106 @@ export const BOOKING_SECTION_SETTINGS_CONFIG =
|
|
|
3295
3302
|
isLocked: false,
|
|
3296
3303
|
});
|
|
3297
3304
|
|
|
3305
|
+
const FAQ_FIELD_GROUP_IDS = {
|
|
3306
|
+
settings: 'settings',
|
|
3307
|
+
items: 'items',
|
|
3308
|
+
style: 'style',
|
|
3309
|
+
} as const;
|
|
3310
|
+
|
|
3311
|
+
export const FAQ_SECTION_SETTINGS_CONFIG =
|
|
3312
|
+
(): ContentSettingsConfig<FaqSectionContent> => ({
|
|
3313
|
+
type: 'faq-section',
|
|
3314
|
+
category: 'general',
|
|
3315
|
+
createInitialContent: createInitialFaqSectionContent,
|
|
3316
|
+
displayMode: CONTENT_SETTINGS_DISPLAY_MODES.focused,
|
|
3317
|
+
defaultIconName: 'question-circle-filled',
|
|
3318
|
+
displayName: contentSettingsTr(`faqSectionDisplayName`),
|
|
3319
|
+
fieldGroups: [
|
|
3320
|
+
{
|
|
3321
|
+
id: FAQ_FIELD_GROUP_IDS.settings,
|
|
3322
|
+
displayName: contentSettingsTr(`settingsDisplayName`),
|
|
3323
|
+
isCollapsed: false,
|
|
3324
|
+
},
|
|
3325
|
+
{
|
|
3326
|
+
id: FAQ_FIELD_GROUP_IDS.items,
|
|
3327
|
+
displayName: contentSettingsTr(`faqItemsDisplayName`),
|
|
3328
|
+
isCollapsed: false,
|
|
3329
|
+
},
|
|
3330
|
+
{
|
|
3331
|
+
id: FAQ_FIELD_GROUP_IDS.style,
|
|
3332
|
+
displayName: contentSettingsTr(`styleDisplayName`),
|
|
3333
|
+
isCollapsed: true,
|
|
3334
|
+
},
|
|
3335
|
+
],
|
|
3336
|
+
fields: {
|
|
3337
|
+
titleStyle: DEFAULT_TITLE_STYLE_SETTINGS_FILED_WITH_TITLE(),
|
|
3338
|
+
descriptionStyle: DEFAULT_DESCRIPTION_STYLE_FILED(),
|
|
3339
|
+
title: {
|
|
3340
|
+
type: 'text',
|
|
3341
|
+
placeholder: contentSettingsTr(`titlePlaceholder`),
|
|
3342
|
+
title: contentSettingsTr(`titleTitle`),
|
|
3343
|
+
groupId: FAQ_FIELD_GROUP_IDS.settings,
|
|
3344
|
+
maxLength: 200,
|
|
3345
|
+
},
|
|
3346
|
+
description: {
|
|
3347
|
+
type: 'textarea',
|
|
3348
|
+
placeholder: contentSettingsTr(`descriptionPlaceholder`),
|
|
3349
|
+
title: contentSettingsTr(`descriptionTitle`),
|
|
3350
|
+
groupId: FAQ_FIELD_GROUP_IDS.settings,
|
|
3351
|
+
maxLength: 1000,
|
|
3352
|
+
},
|
|
3353
|
+
items: {
|
|
3354
|
+
type: 'list-items',
|
|
3355
|
+
defaultValue: [],
|
|
3356
|
+
groupId: FAQ_FIELD_GROUP_IDS.items,
|
|
3357
|
+
maxLength: FAQ_MAX_ITEMS,
|
|
3358
|
+
itemFields: [
|
|
3359
|
+
{
|
|
3360
|
+
key: 'question',
|
|
3361
|
+
kind: 'text',
|
|
3362
|
+
styleKey: 'questionStyle',
|
|
3363
|
+
defaultStyle: () => createInitialFaqQuestionStyle(),
|
|
3364
|
+
maxLength: 200,
|
|
3365
|
+
title: contentSettingsTr(`faqQuestionTitle`),
|
|
3366
|
+
placeholder: contentSettingsTr(`faqQuestionPlaceholder`),
|
|
3367
|
+
defaultValue: () => contentSettingsTr(`faqNewQuestion`),
|
|
3368
|
+
},
|
|
3369
|
+
{
|
|
3370
|
+
key: 'answer',
|
|
3371
|
+
kind: 'textarea',
|
|
3372
|
+
styleKey: 'answerStyle',
|
|
3373
|
+
defaultStyle: () => createInitialFaqAnswerStyle(),
|
|
3374
|
+
maxLength: 1000,
|
|
3375
|
+
title: contentSettingsTr(`faqAnswerTitle`),
|
|
3376
|
+
placeholder: contentSettingsTr(`faqAnswerPlaceholder`),
|
|
3377
|
+
defaultValue: () => contentSettingsTr(`faqNewAnswer`),
|
|
3378
|
+
},
|
|
3379
|
+
],
|
|
3380
|
+
},
|
|
3381
|
+
displayStyle: {
|
|
3382
|
+
type: 'radio',
|
|
3383
|
+
role: 'multi',
|
|
3384
|
+
defaultValue: FAQ_DISPLAY_STYLES.centered,
|
|
3385
|
+
title: contentSettingsTr(`displayStyleTitle`),
|
|
3386
|
+
optionsConvertor: faqDisplayStyleConvertor,
|
|
3387
|
+
groupId: FAQ_FIELD_GROUP_IDS.style,
|
|
3388
|
+
variant: 'icon',
|
|
3389
|
+
},
|
|
3390
|
+
...PADDING_CONTROL_FIELDS(FAQ_FIELD_GROUP_IDS.style),
|
|
3391
|
+
backgroundStyle: {
|
|
3392
|
+
type: 'color',
|
|
3393
|
+
groupId: FAQ_FIELD_GROUP_IDS.style,
|
|
3394
|
+
defaultValue: {},
|
|
3395
|
+
isInline: true,
|
|
3396
|
+
showToggle: false,
|
|
3397
|
+
title: contentSettingsTr(`backgroundColorTitle`),
|
|
3398
|
+
valueConvertor: backgroundColorConvertor,
|
|
3399
|
+
},
|
|
3400
|
+
},
|
|
3401
|
+
isEnabled: true,
|
|
3402
|
+
isLocked: false,
|
|
3403
|
+
});
|
|
3404
|
+
|
|
3298
3405
|
export const CONTENT_SETTINGS_CONFIGS = (): Record<
|
|
3299
3406
|
ContentType,
|
|
3300
3407
|
ContentSettingsConfig<any>
|
|
@@ -3331,4 +3438,5 @@ export const CONTENT_SETTINGS_CONFIGS = (): Record<
|
|
|
3331
3438
|
'shapes-section': SHAPES_SECTION_SETTINGS_CONFIG(),
|
|
3332
3439
|
'shop-section': SHOP_SECTION_SETTINGS_CONFIG(),
|
|
3333
3440
|
'booking-section': BOOKING_SECTION_SETTINGS_CONFIG(),
|
|
3441
|
+
'faq-section': FAQ_SECTION_SETTINGS_CONFIG(),
|
|
3334
3442
|
});
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
import { createPinia, setActivePinia } from 'pinia';
|
|
3
|
+
import {
|
|
4
|
+
BRAND_PAGE_TYPES,
|
|
5
|
+
FAQ_DISPLAY_STYLES,
|
|
6
|
+
FAQ_MAX_ITEMS,
|
|
7
|
+
} from '@brand-page';
|
|
8
|
+
import { FAQ_SECTION_SETTINGS_CONFIG } from './config-settings-constant';
|
|
9
|
+
import { createInitialFaqSectionContent } from '../models/content-settings';
|
|
10
|
+
import { faqDisplayStyleConvertor } from '../convertors/faq-display-style.convertor';
|
|
11
|
+
import { getEnabledContentSettingsConfigs } from '../stores/brandpage-maker/brandpage-maker-store-utils';
|
|
12
|
+
import { useBrandPageMakerStore } from '../stores/brandpage-maker/brandpage-maker-store';
|
|
13
|
+
import { RTE_ITEM_FIELD_PAIRS } from '@shared/color-strategies/rte-field-pairs';
|
|
14
|
+
|
|
15
|
+
// Tests load no translation bundles; return the key so defaults are assertable.
|
|
16
|
+
vi.mock('@src/composables/useTranslate', async (importOriginal) => ({
|
|
17
|
+
...(await importOriginal<Record<string, unknown>>()),
|
|
18
|
+
contentSettingsTr: (key: string) => key,
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
describe('FAQ section config', () => {
|
|
22
|
+
test('is a General block with no website-type restriction', () => {
|
|
23
|
+
const config = FAQ_SECTION_SETTINGS_CONFIG();
|
|
24
|
+
|
|
25
|
+
expect(config.category).toBe('general');
|
|
26
|
+
expect(config.brandPageType).toBeUndefined();
|
|
27
|
+
expect(config.defaultIconName).toBe('question-circle-filled');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test.each([
|
|
31
|
+
BRAND_PAGE_TYPES.default,
|
|
32
|
+
BRAND_PAGE_TYPES.brandSite,
|
|
33
|
+
BRAND_PAGE_TYPES.brandContact,
|
|
34
|
+
])('is offered in Add Content on %s', (brandPageType) => {
|
|
35
|
+
setActivePinia(createPinia());
|
|
36
|
+
useBrandPageMakerStore().$patch({ brandPageType });
|
|
37
|
+
|
|
38
|
+
const types = getEnabledContentSettingsConfigs().map((c) => c.type);
|
|
39
|
+
|
|
40
|
+
expect(types).toContain('faq-section');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('caps items at 6 and labels rows by question', () => {
|
|
44
|
+
const items = FAQ_SECTION_SETTINGS_CONFIG().fields.items as any;
|
|
45
|
+
|
|
46
|
+
expect(items.type).toBe('list-items');
|
|
47
|
+
expect(items.maxLength).toBe(FAQ_MAX_ITEMS);
|
|
48
|
+
expect(FAQ_MAX_ITEMS).toBe(6);
|
|
49
|
+
expect(items.itemFields.map((f: any) => [f.key, f.kind])).toEqual([
|
|
50
|
+
['question', 'text'],
|
|
51
|
+
['answer', 'textarea'],
|
|
52
|
+
]);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('question and answer are rich text with their own per-item style, capped like title and description', () => {
|
|
56
|
+
const items = FAQ_SECTION_SETTINGS_CONFIG().fields.items as any;
|
|
57
|
+
|
|
58
|
+
expect(
|
|
59
|
+
items.itemFields.map((f: any) => [f.key, f.styleKey, f.maxLength]),
|
|
60
|
+
).toEqual([
|
|
61
|
+
['question', 'questionStyle', 200],
|
|
62
|
+
['answer', 'answerStyle', 1000],
|
|
63
|
+
]);
|
|
64
|
+
expect(
|
|
65
|
+
items.itemFields.map((f: any) => f.defaultStyle().textStyleType),
|
|
66
|
+
).toEqual(['headings', 'paragraphs']);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('has no section-level Question/Answer style — each item carries its own', () => {
|
|
70
|
+
const { fields } = FAQ_SECTION_SETTINGS_CONFIG() as any;
|
|
71
|
+
|
|
72
|
+
expect(fields.questionStyle).toBeUndefined();
|
|
73
|
+
expect(fields.answerStyle).toBeUndefined();
|
|
74
|
+
expect(RTE_ITEM_FIELD_PAIRS['faq-section']).toEqual([
|
|
75
|
+
{
|
|
76
|
+
itemsField: 'items',
|
|
77
|
+
textField: 'question',
|
|
78
|
+
styleField: 'questionStyle',
|
|
79
|
+
},
|
|
80
|
+
{ itemsField: 'items', textField: 'answer', styleField: 'answerStyle' },
|
|
81
|
+
]);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('createInitialFaqSectionContent', () => {
|
|
86
|
+
test('starts with one sample item and the demo defaults', () => {
|
|
87
|
+
const content = createInitialFaqSectionContent({
|
|
88
|
+
brandPageType: BRAND_PAGE_TYPES.brandSite,
|
|
89
|
+
} as any);
|
|
90
|
+
|
|
91
|
+
expect(content.type).toBe('faq-section');
|
|
92
|
+
expect(content.displayStyle).toBe(FAQ_DISPLAY_STYLES.centered);
|
|
93
|
+
expect(content.topPadding).toBe(32);
|
|
94
|
+
expect(content.bottomPadding).toBe(32);
|
|
95
|
+
expect(content.backgroundStyle).toEqual({});
|
|
96
|
+
expect(content.items).toHaveLength(1);
|
|
97
|
+
expect(content.items[0]).toMatchObject({
|
|
98
|
+
id: expect.any(String),
|
|
99
|
+
question: 'defaultFaqQuestion',
|
|
100
|
+
answer: 'defaultFaqAnswer',
|
|
101
|
+
});
|
|
102
|
+
expect(content.titleStyle.textStyleType).toBe('titles');
|
|
103
|
+
expect(content.descriptionStyle.textStyleType).toBe('paragraphs');
|
|
104
|
+
content.items.forEach((item) => {
|
|
105
|
+
expect(item.questionStyle).toEqual({
|
|
106
|
+
applyAutoScale: true,
|
|
107
|
+
textStyleType: 'headings',
|
|
108
|
+
textAlign: 'left',
|
|
109
|
+
});
|
|
110
|
+
expect(item.answerStyle).toEqual({
|
|
111
|
+
applyAutoScale: true,
|
|
112
|
+
textStyleType: 'paragraphs',
|
|
113
|
+
textAlign: 'left',
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('faqDisplayStyleConvertor', () => {
|
|
120
|
+
test('offers the three styles with their icons', () => {
|
|
121
|
+
const { options } = faqDisplayStyleConvertor.convert(
|
|
122
|
+
FAQ_DISPLAY_STYLES.split,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
expect(
|
|
126
|
+
options.map((o: any) => [o.value, o.iconName, o.isSelected]),
|
|
127
|
+
).toEqual([
|
|
128
|
+
[FAQ_DISPLAY_STYLES.centered, 'display-style-faq-1', false],
|
|
129
|
+
[FAQ_DISPLAY_STYLES.split, 'display-style-faq-2', true],
|
|
130
|
+
[FAQ_DISPLAY_STYLES.grid, 'display-style-faq-3', false],
|
|
131
|
+
]);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test.each([
|
|
135
|
+
[FAQ_DISPLAY_STYLES.centered, 'center'],
|
|
136
|
+
[FAQ_DISPLAY_STYLES.split, 'left'],
|
|
137
|
+
[FAQ_DISPLAY_STYLES.grid, 'center'],
|
|
138
|
+
])(
|
|
139
|
+
'switching to %s only moves the display style and heading alignment',
|
|
140
|
+
(value, textAlign) => {
|
|
141
|
+
const config = faqDisplayStyleConvertor.convert(value);
|
|
142
|
+
const result = faqDisplayStyleConvertor.convertBack(config);
|
|
143
|
+
|
|
144
|
+
expect(result).toEqual({
|
|
145
|
+
displayStyle: value,
|
|
146
|
+
titleStyle: { textAlign },
|
|
147
|
+
descriptionStyle: { textAlign },
|
|
148
|
+
});
|
|
149
|
+
},
|
|
150
|
+
);
|
|
151
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ButtonGroupConfig, ValueConvertor } from '../models';
|
|
2
|
+
import { FAQ_DISPLAY_STYLES } from '@brand-page/constants';
|
|
3
|
+
import type { FaqSectionContent } from '@brand-page/models';
|
|
4
|
+
import { converterTr } from '@src/composables/useTranslate';
|
|
5
|
+
|
|
6
|
+
const ICON_VIEW_BOX = '0 0 96 56';
|
|
7
|
+
|
|
8
|
+
export const faqDisplayStyleConvertor: ValueConvertor<
|
|
9
|
+
string | null,
|
|
10
|
+
ButtonGroupConfig,
|
|
11
|
+
Partial<FaqSectionContent>
|
|
12
|
+
> = {
|
|
13
|
+
convertBackToMultipleValues: true,
|
|
14
|
+
convert(value: string | null): ButtonGroupConfig {
|
|
15
|
+
return {
|
|
16
|
+
options: [
|
|
17
|
+
{
|
|
18
|
+
title: converterTr(`faqCenteredAccordion`),
|
|
19
|
+
value: FAQ_DISPLAY_STYLES.centered,
|
|
20
|
+
isSelected: value === FAQ_DISPLAY_STYLES.centered,
|
|
21
|
+
iconName: 'display-style-faq-1',
|
|
22
|
+
iconViewBox: ICON_VIEW_BOX,
|
|
23
|
+
dataAttribute: 'data-test-btn-faq-centered',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
title: converterTr(`faqSplitAccordion`),
|
|
27
|
+
value: FAQ_DISPLAY_STYLES.split,
|
|
28
|
+
isSelected: value === FAQ_DISPLAY_STYLES.split,
|
|
29
|
+
iconName: 'display-style-faq-2',
|
|
30
|
+
iconViewBox: ICON_VIEW_BOX,
|
|
31
|
+
dataAttribute: 'data-test-btn-faq-split',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
title: converterTr(`faqGrid`),
|
|
35
|
+
value: FAQ_DISPLAY_STYLES.grid,
|
|
36
|
+
isSelected: value === FAQ_DISPLAY_STYLES.grid,
|
|
37
|
+
iconName: 'display-style-faq-3',
|
|
38
|
+
iconViewBox: ICON_VIEW_BOX,
|
|
39
|
+
dataAttribute: 'data-test-btn-faq-grid',
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
// The heading sits left beside the accordion in split, centred above it otherwise.
|
|
46
|
+
convertBack(config: ButtonGroupConfig): Partial<FaqSectionContent> {
|
|
47
|
+
const displayStyle =
|
|
48
|
+
config.options.find((v) => v.isSelected)?.value ??
|
|
49
|
+
FAQ_DISPLAY_STYLES.centered;
|
|
50
|
+
const textAlign =
|
|
51
|
+
displayStyle === FAQ_DISPLAY_STYLES.split ? 'left' : 'center';
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
displayStyle,
|
|
55
|
+
titleStyle: { textAlign },
|
|
56
|
+
descriptionStyle: { textAlign },
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
};
|