@designcrowd/library.brand-page 6.0.25 → 6.0.26-json-prereq-2
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-CS3ct0wa.js → CreatedOnBrandCrowd-de-de-CKBqjDH3.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-CmBcnDu6.js → CreatedOnBrandCrowd-en-us-CRXiimvT.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-BdTuJtqV.js → CreatedOnBrandCrowd-es-es-DCYdY6sj.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-Cx_H9X6l.js → CreatedOnBrandCrowd-fr-ca-Dk7LOhxE.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-Cx_H9X6l.js → CreatedOnBrandCrowd-fr-fr-Dk7LOhxE.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-BZZ9hjUi.js → CreatedOnBrandCrowd-pt-br-Cp4ufHJP.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-BZZ9hjUi.js → CreatedOnBrandCrowd-pt-pt-Cp4ufHJP.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-SbONDQN1.js → CreatedOnDcom-de-de-ZSLkWMwM.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-Beno1_gw.js → CreatedOnDcom-en-us-BgdIGfT3.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-BBE_zdRu.js → CreatedOnDcom-es-es-D0KemkCZ.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-C6pgDB5x.js → CreatedOnDcom-fr-ca-BuwNjNbC.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-FD1eqtg3.js → CreatedOnDcom-fr-fr-DCQcsFPf.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-BiSx3OwM.js → CreatedOnDcom-pt-br-DD-oLAS1.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-Dn4DmKGA.js → CreatedOnDcom-pt-pt-D8qLq2wW.js} +1 -1
- package/lib/src/brand-page/components/contact-form/ContactForm.mixin.js +5 -2
- package/lib/src/brand-page/models/index.d.ts +34 -26
- package/lib/src/brand-page/utils/migration/migration-20.d.ts +2 -0
- package/lib/src/brand-page/utils/migration/migration-20.js +66 -0
- package/lib/src/brand-page/utils/migration.util.js +11 -0
- package/lib/src/brand-page/utils/text.util.d.ts +1 -1
- package/lib/src/brand-page/utils/text.util.js +32 -0
- package/lib/src/brand-page/utils/vcard.util.js +4 -4
- package/lib/src/brand-page/utils/view-model.util.d.ts +1 -0
- package/lib/src/brand-page/utils/view-model.util.js +68 -20
- package/lib/src/brand-page/view-models.d.ts +3 -3
- package/lib/src/brand-page-maker/__fixtures__/complex-rte.fixture.d.ts +22 -0
- package/lib/src/brand-page-maker/__fixtures__/complex-rte.fixture.js +22 -0
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.d.ts +0 -1
- package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +21 -9
- package/lib/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.d.ts +2 -9
- package/lib/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.js +6 -10
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.d.ts +14 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.js +39 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.d.ts +28 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.js +90 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +1 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +24 -103
- package/lib/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.d.ts +8 -2
- package/lib/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.js +20 -0
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +7 -0
- package/lib/src/brand-page-maker/utils/index.d.ts +2 -0
- package/lib/src/brand-page-maker/utils/index.js +2 -0
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +28 -5
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +48 -5
- package/lib/src/brand-page-maker/utils/rte-render.util.d.ts +63 -0
- package/lib/src/brand-page-maker/utils/rte-render.util.js +95 -0
- package/lib/src/brand-page-maker/utils/rte-sanitize.util.d.ts +6 -0
- package/lib/src/brand-page-maker/utils/rte-sanitize.util.js +158 -0
- package/lib/src/brand-page-maker/validators/field.validator.js +10 -2
- package/lib/src/css/library.brand-page-brandCrowd.min.css +39 -39
- package/lib/src/css/library.brand-page-brandPage.min.css +39 -39
- package/lib/src/css/library.brand-page-designCom.min.css +39 -39
- package/lib/src/css/library.brand-page-preview.min.css +39 -39
- package/lib/src/index.d.ts +1 -0
- package/lib/src/index.mjs +143 -138
- package/lib/src/{lib-BVHFYSLL.js → lib-Db6j9fQZ.js} +56262 -52768
- package/lib/src/lib.js +2 -0
- package/lib/src/metadata-builder/ai-metadata-executor.d.ts +0 -1
- package/lib/src/metadata-builder/ai-metadata-executor.js +0 -19
- package/lib/src/metadata-builder/builders/section-builders/about-section-builder.js +2 -3
- package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.js +2 -3
- package/lib/src/metadata-builder/builders/section-builders/booking-section-builder.js +2 -3
- package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.js +3 -4
- package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +2 -3
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.js +1 -2
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.js +1 -2
- package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.js +3 -4
- package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +2 -3
- package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +1 -2
- package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +15 -11
- package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +11 -13
- package/lib/src/metadata-builder/helpers/rte.helpers.js +14 -73
- package/lib/src/metadata-builder/metadata-executor.js +0 -4
- package/lib/src/metadata-builder/models.d.ts +0 -2
- package/lib/src/metadata-builder/models.js +0 -2
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +0 -19
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.js +0 -4
- package/lib/src/metadata-builder/sanitizers/rte-schema-check.d.ts +7 -8
- package/lib/src/metadata-builder/sanitizers/rte-schema-check.js +21 -52
- package/lib/src/shared/content-settings/components/GenericTextInput.mixin.d.ts +2 -2
- package/lib/src/shared/content-settings/components/GenericTextInput.mixin.js +14 -1
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +12 -3
- package/lib/src/shared/content-settings/components/email-field/EmailField.mixin.d.ts +2 -2
- package/lib/src/shared/content-settings/components/radio-field/RadioField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/slider-field/SliderField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/tel-field/TelField.mixin.d.ts +2 -2
- package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.d.ts +3 -2
- package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.js +10 -3
- package/lib/src/shared/content-settings/components/text-field/TextField.mixin.d.ts +2 -2
- package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.d.ts +2 -1
- package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.js +4 -1
- package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +2 -2
- package/lib/src/shared/content-settings/components/url-field/UrlField.mixin.d.ts +2 -2
- package/lib/src/shared/content-settings/components/youtube-video-field/YoutubeVideoField.mixin.d.ts +2 -2
- package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +1 -1
- package/lib/src/utils/minify-brand-page-metadata.js +4 -1
- package/package.json +17 -15
- package/src/brand-page/components/contact-form/ContactForm.mixin.ts +5 -2
- package/src/brand-page/components/text-wrapper/TextWrapper.vue +17 -6
- package/src/brand-page/models/index.ts +35 -26
- package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -3
- package/src/brand-page/utils/migration/migration-20.server.test.ts +125 -0
- package/src/brand-page/utils/migration/migration-20.test.ts +72 -0
- package/src/brand-page/utils/migration/migration-20.ts +87 -0
- package/src/brand-page/utils/migration.util.ts +12 -0
- package/src/brand-page/utils/style.util.test.ts +51 -0
- package/src/brand-page/utils/text.util.test.ts +47 -0
- package/src/brand-page/utils/text.util.ts +43 -4
- package/src/brand-page/utils/vcard.util.ts +6 -4
- package/src/brand-page/utils/view-model.pageid-rte.test.ts +104 -0
- package/src/brand-page/utils/view-model.util.ts +94 -26
- package/src/brand-page/view-models.ts +3 -2
- package/src/brand-page-maker/__fixtures__/complex-rte.fixture.ts +23 -0
- package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +4 -3
- package/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.ts +0 -1
- package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +28 -9
- package/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.ts +6 -10
- package/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.test.ts +52 -0
- package/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.ts +42 -0
- package/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.ts +137 -0
- package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +27 -111
- package/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.ts +23 -0
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +8 -0
- package/src/brand-page-maker/utils/__snapshots__/rte-render-parity.test.ts.snap +202 -0
- package/src/brand-page-maker/utils/index.ts +2 -0
- package/src/brand-page-maker/utils/rich-text-editor.util.test.ts +37 -3
- package/src/brand-page-maker/utils/rich-text-editor.util.ts +66 -11
- package/src/brand-page-maker/utils/rte-features.test.ts +351 -0
- package/src/brand-page-maker/utils/rte-render-parity.test.ts +157 -0
- package/src/brand-page-maker/utils/rte-render.util.ts +165 -0
- package/src/brand-page-maker/utils/rte-sanitize-json.test.ts +158 -0
- package/src/brand-page-maker/utils/rte-sanitize.util.ts +195 -0
- package/src/brand-page-maker/validators/field.validator.test.ts +55 -0
- package/src/brand-page-maker/validators/field.validator.ts +10 -2
- package/src/lib.ts +9 -0
- package/src/metadata-builder/ai-metadata-executor.ts +0 -26
- package/src/metadata-builder/builders/section-builders/about-section-builder.ts +2 -3
- package/src/metadata-builder/builders/section-builders/banner-section-builder.ts +2 -3
- package/src/metadata-builder/builders/section-builders/booking-section-builder.ts +2 -5
- package/src/metadata-builder/builders/section-builders/contact-form-builder.ts +3 -4
- package/src/metadata-builder/builders/section-builders/images-section-builder.ts +2 -3
- package/src/metadata-builder/builders/section-builders/mailing-list-builder.ts +1 -2
- package/src/metadata-builder/builders/section-builders/mailing-list-section-builder.ts +1 -2
- package/src/metadata-builder/builders/section-builders/profile-section-builder.ts +3 -6
- package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +2 -3
- package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +1 -2
- package/src/metadata-builder/builders/section-builders/text-section-builder.ts +19 -13
- package/src/metadata-builder/helpers/rte.helpers.ts +15 -101
- package/src/metadata-builder/metadata-executor.ts +0 -5
- package/src/metadata-builder/models.ts +0 -3
- package/src/metadata-builder/parsers/ai-toolcall-parser.ts +0 -27
- package/src/metadata-builder/sanitizers/rte-schema-check.ts +24 -53
- package/src/shared/content-settings/components/GenericTextInput.mixin.ts +17 -1
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +16 -3
- package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.ts +13 -4
- package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.vue +6 -4
- package/src/shared/content-settings/components/text-image-field/TextImageField.vue +6 -3
- package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.ts +6 -1
- package/src/shared/content-settings/components/text-items-field/TextItemsField.vue +1 -1
- package/src/utils/minify-brand-page-metadata.ts +4 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontSize.d.ts +0 -20
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontSize.js +0 -44
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/LineHeight.d.ts +0 -27
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/LineHeight.js +0 -44
- package/lib/src/metadata-builder/builders/update-content-text-builder.d.ts +0 -17
- package/lib/src/metadata-builder/builders/update-content-text-builder.js +0 -103
- package/lib/src/metadata-builder/builders/update-content-text-style-builder.d.ts +0 -16
- package/lib/src/metadata-builder/builders/update-content-text-style-builder.js +0 -216
- package/src/brand-page-maker/composables/rich-text-editor/extensions/FontSize.ts +0 -73
- package/src/brand-page-maker/composables/rich-text-editor/extensions/LineHeight.ts +0 -85
- package/src/metadata-builder/builders/update-content-text-builder.ts +0 -148
- package/src/metadata-builder/builders/update-content-text-style-builder.ts +0 -352
|
@@ -1,73 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import Underline from '@tiptap/extension-underline';
|
|
4
|
-
import TextStyle from '@tiptap/extension-text-style';
|
|
5
|
-
import TextAlign from '@tiptap/extension-text-align';
|
|
6
|
-
import FontFamily from '@tiptap/extension-font-family';
|
|
7
|
-
import ColorExtension from '@tiptap/extension-color';
|
|
8
|
-
import Highlight from '@tiptap/extension-highlight';
|
|
9
|
-
import Link from '@tiptap/extension-link';
|
|
10
|
-
import { FontSize } from '../../brand-page-maker/composables/rich-text-editor/extensions/FontSize';
|
|
11
|
-
import { LetterSpacing } from '../../brand-page-maker/composables/rich-text-editor/extensions/LetterSpacing';
|
|
12
|
-
import { LineHeight } from '../../brand-page-maker/composables/rich-text-editor/extensions/LineHeight';
|
|
13
|
-
import { AutoLink } from '../../brand-page-maker/composables/rich-text-editor/extensions/AutoLink';
|
|
1
|
+
import { getSchema } from '@tiptap/core';
|
|
2
|
+
import { getRteExtensions } from '../../brand-page-maker/composables/rich-text-editor/getRteExtensions';
|
|
14
3
|
import { isTiptapDocument } from '../parsers/section-tool-arguments';
|
|
15
4
|
import { rteStyleCheck, textCheck, } from './section-args-validator';
|
|
16
5
|
/**
|
|
17
|
-
*
|
|
18
|
-
* `
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
6
|
+
* The ProseMirror schema built from the SAME extension set the editor and
|
|
7
|
+
* renderer use (`getRteExtensions`), so validation matches real editor output.
|
|
8
|
+
* `getSchema` is DOM-less (no Editor instance) and the schema is pure, so it is
|
|
9
|
+
* built once and cached.
|
|
10
|
+
*
|
|
11
|
+
* We import `getRteExtensions` (a leaf module — @tiptap + prosemirror only), not
|
|
12
|
+
* the maker composable (`useExternalRichTextEditor`), which would pull in the
|
|
13
|
+
* AI executor → section-builders → section-rules graph and re-enter this file
|
|
14
|
+
* before its exports are bound.
|
|
22
15
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
extensions: [
|
|
26
|
-
StarterKit,
|
|
27
|
-
Underline,
|
|
28
|
-
TextStyle.configure({ mergeNestedSpanStyles: true }),
|
|
29
|
-
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
|
30
|
-
FontFamily.configure({ types: ['textStyle'] }),
|
|
31
|
-
FontSize,
|
|
32
|
-
LetterSpacing,
|
|
33
|
-
LineHeight,
|
|
34
|
-
ColorExtension.configure({ types: ['textStyle'] }),
|
|
35
|
-
Highlight.configure({ multicolor: true }),
|
|
36
|
-
Link.configure({
|
|
37
|
-
openOnClick: false,
|
|
38
|
-
defaultProtocol: 'https',
|
|
39
|
-
autolink: true,
|
|
40
|
-
}),
|
|
41
|
-
AutoLink,
|
|
42
|
-
],
|
|
43
|
-
});
|
|
16
|
+
let cachedSchema;
|
|
17
|
+
const getRteSchema = () => (cachedSchema ??= getSchema(getRteExtensions({ includeLinkRel: true })));
|
|
44
18
|
/**
|
|
45
|
-
* Validates a Tiptap doc against the
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* the doc to `<p></p>` (BP-5669).
|
|
19
|
+
* Validates a Tiptap doc against the real ProseMirror schema
|
|
20
|
+
* (`schema.nodeFromJSON`). Catches malformed AI input — stray non-node children
|
|
21
|
+
* in `content`, unknown node types, malformed attrs — before the builder runs
|
|
22
|
+
* and the renderer's silent `setContent` drops the doc to `<p></p>` (BP-5669).
|
|
50
23
|
*
|
|
51
|
-
* Returns the field-prefixed error string so the AI's tool-call retry
|
|
52
|
-
*
|
|
53
|
-
*
|
|
24
|
+
* Returns the field-prefixed error string so the AI's tool-call retry loop reads
|
|
25
|
+
* it via `BuilderResult.errors` → `tool_result.errorMessage` and re-emits a
|
|
26
|
+
* corrected payload.
|
|
54
27
|
*/
|
|
55
28
|
export const rteSchemaCheck = (field) => (record) => {
|
|
56
29
|
const value = record[field];
|
|
57
30
|
if (!isTiptapDocument(value))
|
|
58
31
|
return null;
|
|
59
|
-
const editor = buildHeadlessEditor();
|
|
60
32
|
try {
|
|
61
|
-
|
|
33
|
+
getRteSchema().nodeFromJSON(value);
|
|
62
34
|
return null;
|
|
63
35
|
}
|
|
64
36
|
catch (err) {
|
|
65
37
|
const detail = err instanceof Error ? err.message : String(err);
|
|
66
38
|
return `"${field}" is not valid Tiptap JSON: ${detail}`;
|
|
67
39
|
}
|
|
68
|
-
finally {
|
|
69
|
-
editor.destroy();
|
|
70
|
-
}
|
|
71
40
|
};
|
|
72
41
|
/**
|
|
73
42
|
* Returns [rteSchemaCheck(field), textCheck(field, max), rteStyleCheck(field)].
|
|
@@ -185,12 +185,12 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
185
185
|
}>, {
|
|
186
186
|
index: number;
|
|
187
187
|
settings: ContentItemFieldSettings;
|
|
188
|
-
|
|
188
|
+
value: string | false | undefined;
|
|
189
189
|
styles: Record<string, any>;
|
|
190
|
+
role: string;
|
|
190
191
|
placeholder: string;
|
|
191
192
|
minLength: number;
|
|
192
193
|
maxLength: number;
|
|
193
|
-
value: string | false | undefined;
|
|
194
194
|
attrs: Record<string, any>;
|
|
195
195
|
isRequired: boolean;
|
|
196
196
|
isToggled: boolean;
|
|
@@ -158,7 +158,20 @@ export default defineComponent({
|
|
|
158
158
|
},
|
|
159
159
|
},
|
|
160
160
|
watch: {
|
|
161
|
-
value(newVal) {
|
|
161
|
+
value(newVal, oldVal) {
|
|
162
|
+
// BP-5787: RTE values are Tiptap JSON objects. The parent (TextItemsField)
|
|
163
|
+
// re-clones its items array (cloneDeep) on ANY change — including a sibling
|
|
164
|
+
// field's style sync — yielding a NEW object reference with identical text
|
|
165
|
+
// content. For objects Vue fires this watcher on reference change, so that
|
|
166
|
+
// spurious re-clone would overwrite `_value` and clobber an in-flight edit
|
|
167
|
+
// (a mark applied but not yet debounced to the store), silently dropping
|
|
168
|
+
// the user's formatting. Strings never hit this (same content = same
|
|
169
|
+
// reference = no fire), so mirror that: ignore re-clones whose content is
|
|
170
|
+
// unchanged from the previous prop value.
|
|
171
|
+
if (this.showRichTextEditor &&
|
|
172
|
+
JSON.stringify(newVal) === JSON.stringify(oldVal)) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
162
175
|
this._value = newVal;
|
|
163
176
|
if (this.showRichTextEditor) {
|
|
164
177
|
const textValue = escapeContentText(this._value);
|
package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ interface CategoryTab {
|
|
|
6
6
|
label: string;
|
|
7
7
|
}
|
|
8
8
|
declare const _default: import("vue").DefineComponent<{}, {
|
|
9
|
-
mode: import("vue").ComputedRef<"images" | "
|
|
9
|
+
mode: import("vue").ComputedRef<"images" | "add" | "pages" | "edit" | "focusedContentItem">;
|
|
10
10
|
pages: import("vue").ComputedRef<{
|
|
11
11
|
id: string;
|
|
12
12
|
title: string;
|
|
@@ -34,7 +34,7 @@ declare const _default: import("vue").DefineComponent<{}, {
|
|
|
34
34
|
selectedItemIndex: import("vue").ComputedRef<number | null>;
|
|
35
35
|
selectedItemValue: import("vue").ComputedRef<string | null>;
|
|
36
36
|
contentType: import("vue").ComputedRef<"website" | "image" | "email" | "phone" | "logo" | "general-link" | "profile" | "video" | "text" | "facebook" | "x" | "instagram" | "youtube" | "linkedin" | "pinterest" | "twitch" | "tiktok" | "map" | "image-gallery" | "mailing-list" | "request-payment" | "support-me" | "contact-form" | "banner-section" | "about-section" | "divider-section" | "images-section" | "testimonial-section" | "social-links" | "shapes-section" | "shop-section" | "booking-section" | undefined>;
|
|
37
|
-
mode: import("vue").ComputedRef<"images" | "
|
|
37
|
+
mode: import("vue").ComputedRef<"images" | "add" | "pages" | "edit" | "focusedContentItem">;
|
|
38
38
|
isAdmin: import("vue").ComputedRef<boolean>;
|
|
39
39
|
contentSettingsStore: import("pinia").Store<"uiContentSettings", import("../../store").ContentSettingsState, {
|
|
40
40
|
contentErrorCount(): number;
|
|
@@ -8,7 +8,7 @@ import { SIDE_BAR_TAB_NAMES } from '@brand-page-maker/constants';
|
|
|
8
8
|
import { ITEM_FIELD_TYPES } from '@brand-page-maker/models';
|
|
9
9
|
import { useUiPageSettingsStore } from '../../../page-settings/store';
|
|
10
10
|
import { PAGE_SECTIONS } from '../../../page-settings/models';
|
|
11
|
-
import { getPlainTextFromRTE, replaceTextInRTE, RTE_ALLOWED_SECTION_TYPES, isRTEManagedStyleField, } from '@brand-page-maker/utils';
|
|
11
|
+
import { getPlainTextFromRTE, replaceTextInRTE, RTE_ALLOWED_SECTION_TYPES, isRTEManagedStyleField, isTiptapDocument, renderRteToHtml, toRteJson, } from '@brand-page-maker/utils';
|
|
12
12
|
import { isDefaultContentText } from '@shared/content-settings/utils';
|
|
13
13
|
import { useUiLogoSettingsStore } from '../../../logo-settings/store';
|
|
14
14
|
const RTE_DISALLOWED_FIELD_NAMES = ['buttonText'];
|
|
@@ -267,8 +267,17 @@ export default defineComponent({
|
|
|
267
267
|
},
|
|
268
268
|
onUseGeneratedText(generatedText) {
|
|
269
269
|
let formattedText = generatedText;
|
|
270
|
-
|
|
271
|
-
|
|
270
|
+
// BP-5787: preserve the field's formatting when dropping in AI text.
|
|
271
|
+
// replaceTextInRTE is HTML-based, so JSON is rendered/parsed around it
|
|
272
|
+
// (cold AI path, shared editor); string fields use it directly.
|
|
273
|
+
if (this.showRichTextEditor) {
|
|
274
|
+
if (isTiptapDocument(this.value)) {
|
|
275
|
+
formattedText =
|
|
276
|
+
toRteJson(replaceTextInRTE(renderRteToHtml(this.value), generatedText)) ?? generatedText;
|
|
277
|
+
}
|
|
278
|
+
else if (typeof this.value === 'string') {
|
|
279
|
+
formattedText = replaceTextInRTE(this.value, generatedText);
|
|
280
|
+
}
|
|
272
281
|
}
|
|
273
282
|
this.contentSettingsStore.updateItemValue({
|
|
274
283
|
id: this.id,
|
|
@@ -182,12 +182,12 @@ declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
182
182
|
}>, {
|
|
183
183
|
index: number;
|
|
184
184
|
settings: import("../../models").ContentItemFieldSettings;
|
|
185
|
-
|
|
185
|
+
value: string | false | undefined;
|
|
186
186
|
styles: Record<string, any>;
|
|
187
|
+
role: string;
|
|
187
188
|
placeholder: string;
|
|
188
189
|
minLength: number;
|
|
189
190
|
maxLength: number;
|
|
190
|
-
value: string | false | undefined;
|
|
191
191
|
attrs: Record<string, any>;
|
|
192
192
|
isRequired: boolean;
|
|
193
193
|
isToggled: boolean;
|
|
@@ -107,9 +107,9 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
107
107
|
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
|
108
108
|
}>, {
|
|
109
109
|
fields: Record<string, MultiFieldOption>;
|
|
110
|
+
value: string | boolean | Record<string, any>;
|
|
110
111
|
placeholder: string;
|
|
111
112
|
variant: string;
|
|
112
|
-
value: string | boolean | Record<string, any>;
|
|
113
113
|
multiple: boolean;
|
|
114
114
|
optionsConvertor: OptionsConvertor<unknown>;
|
|
115
115
|
isRequired: boolean;
|
|
@@ -69,9 +69,9 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
69
69
|
}>> & Readonly<{
|
|
70
70
|
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
|
71
71
|
}>, {
|
|
72
|
+
value: string;
|
|
72
73
|
minLength: number;
|
|
73
74
|
maxLength: number;
|
|
74
75
|
valueConvertor: ValueConvertor<BrandPageCssStyle, number, BrandPageCssStyle>;
|
|
75
|
-
value: string;
|
|
76
76
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
77
77
|
export default _default;
|
|
@@ -182,12 +182,12 @@ declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
182
182
|
}>, {
|
|
183
183
|
index: number;
|
|
184
184
|
settings: import("../../models").ContentItemFieldSettings;
|
|
185
|
-
|
|
185
|
+
value: string | false | undefined;
|
|
186
186
|
styles: Record<string, any>;
|
|
187
|
+
role: string;
|
|
187
188
|
placeholder: string;
|
|
188
189
|
minLength: number;
|
|
189
190
|
maxLength: number;
|
|
190
|
-
value: string | false | undefined;
|
|
191
191
|
attrs: Record<string, any>;
|
|
192
192
|
isRequired: boolean;
|
|
193
193
|
isToggled: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PropType } from 'vue';
|
|
2
|
-
import type { ColorReplacement, Content, LogoTheme, TestimonialItems } from '@brand-page';
|
|
2
|
+
import type { ColorReplacement, Content, LogoTheme, RichTextValue, TestimonialItems } from '@brand-page';
|
|
3
3
|
import type { DebounceHandle } from 'lodash.debounce';
|
|
4
4
|
import type { UpdateItemValuePayload } from '../../models';
|
|
5
5
|
declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
@@ -64,7 +64,8 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
64
64
|
name: string;
|
|
65
65
|
value: string;
|
|
66
66
|
}, index: number): void;
|
|
67
|
-
getItemTextPreview(text:
|
|
67
|
+
getItemTextPreview(text: RichTextValue): string;
|
|
68
|
+
rteTextLength(value: RichTextValue): number;
|
|
68
69
|
getPlainTextValue(index: number): string;
|
|
69
70
|
onCaptureSnapshot(): void;
|
|
70
71
|
}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("update:modelValue" | "capture-preview-snapshot" | "on-intent-image-replace")[], "update:modelValue" | "capture-preview-snapshot" | "on-intent-image-replace", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
@@ -3,7 +3,7 @@ import { EMPTY_TESTIMONIAL, MAX_DESCRIPTION_LENGTH, MAX_LENGTH_ERROR_MESSAGE, MA
|
|
|
3
3
|
import debounce from 'lodash.debounce';
|
|
4
4
|
import cloneDeep from 'lodash.clonedeep';
|
|
5
5
|
import { useSnapshotStore } from '@brand-page-maker/stores';
|
|
6
|
-
import { getPlainTextFromRTE } from '@brand-page-maker/utils';
|
|
6
|
+
import { getPlainTextFromRTE, getRteTextLength } from '@brand-page-maker/utils';
|
|
7
7
|
import { isDefaultContentText } from '../../utils';
|
|
8
8
|
import { decodeHtmlEntities } from '@brand-page/utils';
|
|
9
9
|
import { ESCAPED_NEWLINE_CHARACTER } from '../../../../constants/ui';
|
|
@@ -73,7 +73,9 @@ export default defineComponent({
|
|
|
73
73
|
},
|
|
74
74
|
created() {
|
|
75
75
|
this.options = cloneDeep(this.value);
|
|
76
|
-
|
|
76
|
+
// BP-5787: testimonials may be Tiptap JSON (migrated legacy content), so
|
|
77
|
+
// read visible text via getPlainTextFromRTE rather than `.trim()` on a doc.
|
|
78
|
+
this.isEmpty = this.options.map((option) => getPlainTextFromRTE(option.testimonials).length === 0);
|
|
77
79
|
if (!this.changeDebounce) {
|
|
78
80
|
this.changeDebounce = debounce(this.emitChange, DEBOUNCE_IN_MS);
|
|
79
81
|
}
|
|
@@ -160,7 +162,12 @@ export default defineComponent({
|
|
|
160
162
|
this.emitChange();
|
|
161
163
|
},
|
|
162
164
|
getItemTextPreview(text) {
|
|
163
|
-
|
|
165
|
+
// BP-5787: a JSON doc has no `.replace` — take its visible text first.
|
|
166
|
+
const value = typeof text === 'string' ? text : getPlainTextFromRTE(text);
|
|
167
|
+
return decodeHtmlEntities(value.replace(new RegExp(ESCAPED_NEWLINE_CHARACTER, 'g'), ' '));
|
|
168
|
+
},
|
|
169
|
+
rteTextLength(value) {
|
|
170
|
+
return getRteTextLength(value);
|
|
164
171
|
},
|
|
165
172
|
getPlainTextValue(index) {
|
|
166
173
|
const text = this.options[index]?.testimonials || '';
|
|
@@ -182,12 +182,12 @@ declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
182
182
|
}>, {
|
|
183
183
|
index: number;
|
|
184
184
|
settings: import("../../models").ContentItemFieldSettings;
|
|
185
|
-
|
|
185
|
+
value: string | false | undefined;
|
|
186
186
|
styles: Record<string, any>;
|
|
187
|
+
role: string;
|
|
187
188
|
placeholder: string;
|
|
188
189
|
minLength: number;
|
|
189
190
|
maxLength: number;
|
|
190
|
-
value: string | false | undefined;
|
|
191
191
|
attrs: Record<string, any>;
|
|
192
192
|
isRequired: boolean;
|
|
193
193
|
isToggled: boolean;
|
package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PropType } from 'vue';
|
|
2
|
-
import type { Content, LogoTheme, TextItem, TextStyleDeclaration } from '@brand-page/models';
|
|
2
|
+
import type { Content, LogoTheme, RichTextValue, TextItem, TextStyleDeclaration } from '@brand-page/models';
|
|
3
3
|
import type { DebounceHandle } from 'lodash.debounce';
|
|
4
4
|
declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
5
5
|
id: {
|
|
@@ -79,6 +79,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
79
79
|
name: string;
|
|
80
80
|
value: string;
|
|
81
81
|
}, index: number): void;
|
|
82
|
+
rteTextLength(value: RichTextValue): number;
|
|
82
83
|
getPlainTextValue(index: number): string;
|
|
83
84
|
onCaptureSnapshot(): void;
|
|
84
85
|
}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("capture-preview-snapshot" | "update:model-value")[], "capture-preview-snapshot" | "update:model-value", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
@@ -4,7 +4,7 @@ import debounce from 'lodash.debounce';
|
|
|
4
4
|
import cloneDeep from 'lodash.clonedeep';
|
|
5
5
|
import { decodeHtmlEntities, escapeContentText } from '@brand-page/utils';
|
|
6
6
|
import { useSnapshotStore } from '@brand-page-maker/stores';
|
|
7
|
-
import { getPlainTextFromRTE } from '@brand-page-maker/utils';
|
|
7
|
+
import { getPlainTextFromRTE, getRteTextLength } from '@brand-page-maker/utils';
|
|
8
8
|
import { isDefaultContentText } from '../../utils';
|
|
9
9
|
const DEBOUNCE_IN_MS = 250;
|
|
10
10
|
export default defineComponent({
|
|
@@ -172,6 +172,9 @@ export default defineComponent({
|
|
|
172
172
|
this.options[index][payload.name] = payload.value;
|
|
173
173
|
this.emitChange();
|
|
174
174
|
},
|
|
175
|
+
rteTextLength(value) {
|
|
176
|
+
return getRteTextLength(value);
|
|
177
|
+
},
|
|
175
178
|
getPlainTextValue(index) {
|
|
176
179
|
const text = this.options[index]?.text || '';
|
|
177
180
|
const plainText = getPlainTextFromRTE(text);
|
|
@@ -196,12 +196,12 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
196
196
|
}>, {
|
|
197
197
|
index: number;
|
|
198
198
|
settings: import("../../models").ContentItemFieldSettings;
|
|
199
|
-
|
|
199
|
+
value: string | false | undefined;
|
|
200
200
|
styles: Record<string, any>;
|
|
201
|
+
role: string;
|
|
201
202
|
placeholder: string;
|
|
202
203
|
minLength: number;
|
|
203
204
|
maxLength: number;
|
|
204
|
-
value: string | false | undefined;
|
|
205
205
|
attrs: Record<string, any>;
|
|
206
206
|
isRequired: boolean;
|
|
207
207
|
isToggled: boolean;
|
|
@@ -189,12 +189,12 @@ declare const _default: import("vue").DefineComponent<{}, {}, Record<string, any
|
|
|
189
189
|
}>, {
|
|
190
190
|
index: number;
|
|
191
191
|
settings: import("../../models").ContentItemFieldSettings;
|
|
192
|
-
|
|
192
|
+
value: string | false | undefined;
|
|
193
193
|
styles: Record<string, any>;
|
|
194
|
+
role: string;
|
|
194
195
|
placeholder: string;
|
|
195
196
|
minLength: number;
|
|
196
197
|
maxLength: number;
|
|
197
|
-
value: string | false | undefined;
|
|
198
198
|
attrs: Record<string, any>;
|
|
199
199
|
isRequired: boolean;
|
|
200
200
|
isToggled: boolean;
|
package/lib/src/shared/content-settings/components/youtube-video-field/YoutubeVideoField.mixin.d.ts
CHANGED
|
@@ -185,12 +185,12 @@ declare const _default: import("vue").DefineComponent<{}, {}, Record<string, any
|
|
|
185
185
|
}>, {
|
|
186
186
|
index: number;
|
|
187
187
|
settings: import("../../models").ContentItemFieldSettings;
|
|
188
|
-
|
|
188
|
+
value: string | false | undefined;
|
|
189
189
|
styles: Record<string, any>;
|
|
190
|
+
role: string;
|
|
190
191
|
placeholder: string;
|
|
191
192
|
minLength: number;
|
|
192
193
|
maxLength: number;
|
|
193
|
-
value: string | false | undefined;
|
|
194
194
|
attrs: Record<string, any>;
|
|
195
195
|
isRequired: boolean;
|
|
196
196
|
isToggled: boolean;
|
|
@@ -286,7 +286,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
286
286
|
}[]>;
|
|
287
287
|
selectedTabName: import("vue").ComputedRef<string>;
|
|
288
288
|
isAdmin: import("vue").ComputedRef<boolean>;
|
|
289
|
-
contentSettingsMode: import("vue").ComputedRef<"images" | "
|
|
289
|
+
contentSettingsMode: import("vue").ComputedRef<"images" | "add" | "pages" | "edit" | "focusedContentItem">;
|
|
290
290
|
contentSettingsSelectedItemId: import("vue").ComputedRef<string | null>;
|
|
291
291
|
sideBarStore: import("pinia").Store<"uiSideBar", import("../store").SideBarState, {}, {
|
|
292
292
|
setBrandPageSettingsTabVisibility(payload: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BRAND_PAGE_TYPES, } from '../brand-page/models';
|
|
2
|
-
import { hasRTEContent } from '../brand-page-maker/utils';
|
|
2
|
+
import { hasRTEContent, isTiptapDocument } from '../brand-page-maker/utils';
|
|
3
3
|
import { useExternalRichTextEditor } from '../brand-page-maker/composables/rich-text-editor/useRichTextEditor';
|
|
4
4
|
import { findAssetKey, resolveLogoData, } from './build-asset-manifest';
|
|
5
5
|
const BUTTON_TYPES = [
|
|
@@ -17,6 +17,9 @@ const BUTTON_TYPES = [
|
|
|
17
17
|
'tiktok',
|
|
18
18
|
];
|
|
19
19
|
const convertText = (value, editor) => {
|
|
20
|
+
// Already Tiptap JSON (BP-5787 storage) — keep as-is.
|
|
21
|
+
if (isTiptapDocument(value))
|
|
22
|
+
return value;
|
|
20
23
|
if (typeof value !== 'string' || !value)
|
|
21
24
|
return undefined;
|
|
22
25
|
if (hasRTEContent(value)) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@designcrowd/library.brand-page",
|
|
3
3
|
"description": "A collection of Maker/Designer applications",
|
|
4
|
-
"version": "6.0.
|
|
4
|
+
"version": "6.0.26-json-prereq-2",
|
|
5
5
|
"author": "Design.com Eng",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"type": "module",
|
|
@@ -74,19 +74,20 @@
|
|
|
74
74
|
"@designcrowd/fe-shared-lib": "2.0.7",
|
|
75
75
|
"@pinia/nuxt": "0.11.3",
|
|
76
76
|
"@storybook/react": "9.0.4",
|
|
77
|
-
"@tiptap/extension-bubble-menu": "
|
|
78
|
-
"@tiptap/extension-character-count": "
|
|
79
|
-
"@tiptap/extension-color": "
|
|
80
|
-
"@tiptap/extension-font-family": "
|
|
81
|
-
"@tiptap/extension-hard-break": "
|
|
82
|
-
"@tiptap/extension-highlight": "
|
|
83
|
-
"@tiptap/extension-link": "
|
|
84
|
-
"@tiptap/extension-placeholder": "
|
|
85
|
-
"@tiptap/extension-text-align": "
|
|
86
|
-
"@tiptap/extension-text-style": "
|
|
87
|
-
"@tiptap/extension-underline": "
|
|
88
|
-
"@tiptap/starter-kit": "
|
|
89
|
-
"@tiptap/
|
|
77
|
+
"@tiptap/extension-bubble-menu": "3.28.0",
|
|
78
|
+
"@tiptap/extension-character-count": "3.28.0",
|
|
79
|
+
"@tiptap/extension-color": "3.28.0",
|
|
80
|
+
"@tiptap/extension-font-family": "3.28.0",
|
|
81
|
+
"@tiptap/extension-hard-break": "3.28.0",
|
|
82
|
+
"@tiptap/extension-highlight": "3.28.0",
|
|
83
|
+
"@tiptap/extension-link": "3.28.0",
|
|
84
|
+
"@tiptap/extension-placeholder": "3.28.0",
|
|
85
|
+
"@tiptap/extension-text-align": "3.28.0",
|
|
86
|
+
"@tiptap/extension-text-style": "3.28.0",
|
|
87
|
+
"@tiptap/extension-underline": "3.28.0",
|
|
88
|
+
"@tiptap/starter-kit": "3.28.0",
|
|
89
|
+
"@tiptap/static-renderer": "3.28.0",
|
|
90
|
+
"@tiptap/vue-3": "3.28.0",
|
|
90
91
|
"axios": "1.13.5",
|
|
91
92
|
"chroma-js": "2.4.2",
|
|
92
93
|
"click-outside-vue3": "4.0.1",
|
|
@@ -104,6 +105,7 @@
|
|
|
104
105
|
"http-proxy-middleware": "2.0.6",
|
|
105
106
|
"i18next": "25.8.5",
|
|
106
107
|
"jquery": "3.7.1",
|
|
108
|
+
"jsdom": "27.4.0",
|
|
107
109
|
"lodash.clonedeep": "4.5.0",
|
|
108
110
|
"lodash.debounce": "4.0.8",
|
|
109
111
|
"lodash.throttle": "4.1.1",
|
|
@@ -160,6 +162,7 @@
|
|
|
160
162
|
"@types/google.maps": "3.65.1",
|
|
161
163
|
"@types/istanbul-lib-report": "3.0.3",
|
|
162
164
|
"@types/jquery": "3.5.33",
|
|
165
|
+
"@types/jsdom": "21.1.6",
|
|
163
166
|
"@types/lodash.clonedeep": "4.5.9",
|
|
164
167
|
"@types/mssql": "9.1.9",
|
|
165
168
|
"@types/multer": "1.4.11",
|
|
@@ -198,7 +201,6 @@
|
|
|
198
201
|
"imports-loader": "5.0.0",
|
|
199
202
|
"jest-image-snapshot": "6.5.1",
|
|
200
203
|
"js-base64": "3.7.8",
|
|
201
|
-
"jsdom": "27.4.0",
|
|
202
204
|
"jsdom-global": "3.0.2",
|
|
203
205
|
"lint-staged": "15.2.0",
|
|
204
206
|
"mini-css-extract-plugin": "2.10.0",
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
mutedTextForBackground,
|
|
33
33
|
backgroundColorFromStyle,
|
|
34
34
|
} from '@brand-page/utils';
|
|
35
|
-
import { hasRTEContent } from '@brand-page-maker/utils';
|
|
35
|
+
import { hasRTEContent, getPlainTextFromRTE } from '@brand-page-maker/utils';
|
|
36
36
|
import { useReCaptcha } from '../../composables/recaptcha.composable';
|
|
37
37
|
|
|
38
38
|
export interface FieldValue {
|
|
@@ -180,7 +180,10 @@ export default defineComponent({
|
|
|
180
180
|
},
|
|
181
181
|
|
|
182
182
|
title(): string {
|
|
183
|
-
|
|
183
|
+
// BP-5787: title may be RTE JSON (not a string), so `.trim()` would
|
|
184
|
+
// throw — read the visible text via getPlainTextFromRTE to decide
|
|
185
|
+
// whether to fall back to the default.
|
|
186
|
+
return getPlainTextFromRTE(this.viewModel.title)
|
|
184
187
|
? this.viewModel.title
|
|
185
188
|
: 'Contact Us';
|
|
186
189
|
},
|
|
@@ -21,7 +21,13 @@
|
|
|
21
21
|
</div>
|
|
22
22
|
</template>
|
|
23
23
|
<script setup lang="ts">
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
hasRTEContent,
|
|
26
|
+
getPlainTextFromRTE,
|
|
27
|
+
renderRteToHtml,
|
|
28
|
+
isTiptapDocument,
|
|
29
|
+
type RichTextValue,
|
|
30
|
+
} from '@brand-page-maker/utils';
|
|
25
31
|
import {
|
|
26
32
|
type FluidTextData,
|
|
27
33
|
type TextStyleDeclaration,
|
|
@@ -37,7 +43,8 @@ import {
|
|
|
37
43
|
|
|
38
44
|
interface Props {
|
|
39
45
|
textStyle: TextStyleDeclaration | undefined;
|
|
40
|
-
|
|
46
|
+
// BP-5787: an RTE field is a legacy inline-HTML string or a Tiptap JSON doc.
|
|
47
|
+
text: RichTextValue;
|
|
41
48
|
element?: string;
|
|
42
49
|
slug?: string;
|
|
43
50
|
}
|
|
@@ -79,16 +86,20 @@ const textStyleRTE = computed(() => {
|
|
|
79
86
|
};
|
|
80
87
|
});
|
|
81
88
|
|
|
89
|
+
// Render either form (legacy HTML string or Tiptap JSON) to final HTML.
|
|
90
|
+
// For a string this returns it unchanged, so the legacy path is unaffected.
|
|
91
|
+
const renderedHtml = computed(() => renderRteToHtml(props.text));
|
|
92
|
+
|
|
82
93
|
const isRTEContent = computed(() => {
|
|
83
|
-
return
|
|
94
|
+
return isTiptapDocument(props.text) || hasRTEContent(renderedHtml.value);
|
|
84
95
|
});
|
|
85
96
|
|
|
86
97
|
const sanitizeText = computed(() => {
|
|
87
|
-
if (isRTEContent.value && !getPlainTextFromRTE(
|
|
98
|
+
if (isRTEContent.value && !getPlainTextFromRTE(renderedHtml.value)) {
|
|
88
99
|
return '';
|
|
89
100
|
}
|
|
90
101
|
|
|
91
|
-
return
|
|
102
|
+
return renderedHtml.value;
|
|
92
103
|
});
|
|
93
104
|
|
|
94
105
|
const fontSize = computed<any>(() => props.textStyle.fontSize);
|
|
@@ -160,7 +171,7 @@ const applyScale = () => {
|
|
|
160
171
|
}
|
|
161
172
|
|
|
162
173
|
const fontSizeMatchInRTEText = [
|
|
163
|
-
...
|
|
174
|
+
...renderedHtml.value.matchAll(
|
|
164
175
|
/style="(?:[^"]*?)\bfont-size\s*:\s*(?<fontSize>[^;"']+)[^"]*?"/gm,
|
|
165
176
|
),
|
|
166
177
|
].map((x) => parseFloat(x.groups?.fontSize || '1em'));
|