@designcrowd/library.brand-page 6.0.26-json-prereq-2 → 6.0.27-websitev2-dev-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-CKBqjDH3.js → CreatedOnBrandCrowd-de-de-BpFKOKIo.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-CRXiimvT.js → CreatedOnBrandCrowd-en-us-USGAnC_n.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-DCYdY6sj.js → CreatedOnBrandCrowd-es-es-CvVx3h4H.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-Dk7LOhxE.js → CreatedOnBrandCrowd-fr-ca-BCwamW5a.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-Dk7LOhxE.js → CreatedOnBrandCrowd-fr-fr-BCwamW5a.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-Cp4ufHJP.js → CreatedOnBrandCrowd-pt-br-Bt72hMrQ.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-Cp4ufHJP.js → CreatedOnBrandCrowd-pt-pt-Bt72hMrQ.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-ZSLkWMwM.js → CreatedOnDcom-de-de-BxUDrgG9.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-BgdIGfT3.js → CreatedOnDcom-en-us-wjVp5eOs.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-D0KemkCZ.js → CreatedOnDcom-es-es-CwFL2q5h.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-BuwNjNbC.js → CreatedOnDcom-fr-ca-BPZ2_PNq.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-DCQcsFPf.js → CreatedOnDcom-fr-fr-D0vLOikZ.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-DD-oLAS1.js → CreatedOnDcom-pt-br-CTwbxm9H.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-D8qLq2wW.js → CreatedOnDcom-pt-pt-Cfqf8LaM.js} +1 -1
  15. package/lib/src/brand-page/components/contact-form/ContactForm.mixin.js +2 -5
  16. package/lib/src/brand-page/models/index.d.ts +26 -34
  17. package/lib/src/brand-page/utils/migration.util.js +0 -11
  18. package/lib/src/brand-page/utils/text.util.d.ts +1 -1
  19. package/lib/src/brand-page/utils/text.util.js +0 -32
  20. package/lib/src/brand-page/utils/vcard.util.js +4 -4
  21. package/lib/src/brand-page/utils/view-model.util.d.ts +0 -1
  22. package/lib/src/brand-page/utils/view-model.util.js +20 -68
  23. package/lib/src/brand-page/view-models.d.ts +3 -3
  24. package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.d.ts +1 -0
  25. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +7 -3
  26. package/lib/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.d.ts +9 -2
  27. package/lib/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.js +10 -6
  28. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontSize.d.ts +20 -0
  29. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontSize.js +44 -0
  30. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/LineHeight.d.ts +27 -0
  31. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/LineHeight.js +44 -0
  32. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +1 -1
  33. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +103 -24
  34. package/lib/src/brand-page-maker/utils/index.d.ts +0 -2
  35. package/lib/src/brand-page-maker/utils/index.js +0 -2
  36. package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +5 -28
  37. package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +5 -48
  38. package/lib/src/brand-page-maker/validators/field.validator.js +2 -10
  39. package/lib/src/clients/ai-assistant-client.d.ts +1 -0
  40. package/lib/src/clients/ai-assistant-client.js +1 -0
  41. package/lib/src/css/library.brand-page-brandCrowd.min.css +39 -39
  42. package/lib/src/css/library.brand-page-brandPage.min.css +39 -39
  43. package/lib/src/css/library.brand-page-designCom.min.css +39 -39
  44. package/lib/src/css/library.brand-page-preview.min.css +39 -39
  45. package/lib/src/index.d.ts +0 -1
  46. package/lib/src/index.mjs +138 -143
  47. package/lib/src/{lib-Db6j9fQZ.js → lib-Cg4BExY4.js} +72135 -75458
  48. package/lib/src/lib.js +0 -2
  49. package/lib/src/metadata-builder/ai-metadata-executor.d.ts +1 -0
  50. package/lib/src/metadata-builder/ai-metadata-executor.js +19 -0
  51. package/lib/src/metadata-builder/builders/global-font-propagation.d.ts +28 -0
  52. package/lib/src/metadata-builder/builders/global-font-propagation.js +125 -0
  53. package/lib/src/metadata-builder/builders/global-styles-builder.js +16 -0
  54. package/lib/src/metadata-builder/builders/section-builders/about-section-builder.js +3 -2
  55. package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.js +3 -2
  56. package/lib/src/metadata-builder/builders/section-builders/booking-section-builder.js +3 -2
  57. package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.js +4 -3
  58. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +3 -2
  59. package/lib/src/metadata-builder/builders/section-builders/index.d.ts +1 -0
  60. package/lib/src/metadata-builder/builders/section-builders/index.js +1 -0
  61. package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.js +2 -1
  62. package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.js +2 -1
  63. package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.js +4 -3
  64. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +3 -2
  65. package/lib/src/metadata-builder/builders/section-builders/support-me-builder.d.ts +8 -0
  66. package/lib/src/metadata-builder/builders/section-builders/support-me-builder.js +25 -0
  67. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +2 -1
  68. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +16 -17
  69. package/lib/src/metadata-builder/builders/section-field-maps.js +15 -0
  70. package/lib/src/metadata-builder/builders/section-field-utils.d.ts +6 -1
  71. package/lib/src/metadata-builder/builders/section-field-utils.js +48 -12
  72. package/lib/src/metadata-builder/builders/section-rules/support-me.rules.d.ts +2 -0
  73. package/lib/src/metadata-builder/builders/section-rules/support-me.rules.js +17 -0
  74. package/lib/src/metadata-builder/builders/update-content-text-builder.d.ts +17 -0
  75. package/lib/src/metadata-builder/builders/update-content-text-builder.js +103 -0
  76. package/lib/src/metadata-builder/builders/update-content-text-style-builder.d.ts +16 -0
  77. package/lib/src/metadata-builder/builders/update-content-text-style-builder.js +216 -0
  78. package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +13 -11
  79. package/lib/src/metadata-builder/helpers/rte.helpers.js +73 -14
  80. package/lib/src/metadata-builder/metadata-executor.js +7 -1
  81. package/lib/src/metadata-builder/models.d.ts +4 -0
  82. package/lib/src/metadata-builder/models.js +4 -0
  83. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +20 -0
  84. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.js +8 -0
  85. package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +14 -2
  86. package/lib/src/metadata-builder/sanitizers/rte-schema-check.d.ts +8 -7
  87. package/lib/src/metadata-builder/sanitizers/rte-schema-check.js +52 -21
  88. package/lib/src/shared/content-settings/components/GenericTextInput.mixin.js +1 -14
  89. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +3 -12
  90. package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.d.ts +2 -3
  91. package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.js +3 -10
  92. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.d.ts +1 -2
  93. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.js +1 -4
  94. package/lib/src/utils/minify-brand-page-metadata.js +8 -4
  95. package/package.json +15 -17
  96. package/src/brand-page/components/contact-form/ContactForm.mixin.ts +2 -5
  97. package/src/brand-page/components/text-wrapper/TextWrapper.vue +6 -17
  98. package/src/brand-page/models/index.ts +26 -35
  99. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -3
  100. package/src/brand-page/utils/migration.util.ts +0 -12
  101. package/src/brand-page/utils/style.util.test.ts +0 -51
  102. package/src/brand-page/utils/text.util.ts +4 -43
  103. package/src/brand-page/utils/vcard.util.ts +4 -6
  104. package/src/brand-page/utils/view-model.util.ts +26 -94
  105. package/src/brand-page/view-models.ts +2 -3
  106. package/src/brand-page-maker/components/ai-website-builder/AiWebsiteBuilder.vue +1 -1
  107. package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +3 -4
  108. package/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.ts +1 -0
  109. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +7 -3
  110. package/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.ts +10 -6
  111. package/src/brand-page-maker/composables/rich-text-editor/extensions/FontSize.ts +73 -0
  112. package/src/brand-page-maker/composables/rich-text-editor/extensions/LineHeight.ts +85 -0
  113. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +111 -27
  114. package/src/brand-page-maker/utils/index.ts +0 -2
  115. package/src/brand-page-maker/utils/rich-text-editor.util.test.ts +3 -37
  116. package/src/brand-page-maker/utils/rich-text-editor.util.ts +11 -66
  117. package/src/brand-page-maker/validators/field.validator.ts +2 -10
  118. package/src/clients/ai-assistant-client.ts +1 -0
  119. package/src/lib.ts +0 -9
  120. package/src/metadata-builder/ai-metadata-executor.ts +26 -0
  121. package/src/metadata-builder/builders/global-font-propagation.test.ts +269 -0
  122. package/src/metadata-builder/builders/global-font-propagation.ts +205 -0
  123. package/src/metadata-builder/builders/global-styles-builder.ts +21 -0
  124. package/src/metadata-builder/builders/section-builders/about-section-builder.ts +3 -2
  125. package/src/metadata-builder/builders/section-builders/banner-section-builder.ts +3 -2
  126. package/src/metadata-builder/builders/section-builders/booking-section-builder.ts +5 -2
  127. package/src/metadata-builder/builders/section-builders/contact-form-builder.ts +4 -3
  128. package/src/metadata-builder/builders/section-builders/images-section-builder.ts +3 -2
  129. package/src/metadata-builder/builders/section-builders/index.ts +1 -0
  130. package/src/metadata-builder/builders/section-builders/mailing-list-builder.ts +2 -1
  131. package/src/metadata-builder/builders/section-builders/mailing-list-section-builder.ts +2 -1
  132. package/src/metadata-builder/builders/section-builders/profile-section-builder.ts +6 -3
  133. package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +3 -2
  134. package/src/metadata-builder/builders/section-builders/support-me-builder.test.ts +177 -0
  135. package/src/metadata-builder/builders/section-builders/support-me-builder.ts +43 -0
  136. package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +2 -1
  137. package/src/metadata-builder/builders/section-builders/text-section-builder.ts +18 -21
  138. package/src/metadata-builder/builders/section-field-maps.ts +18 -0
  139. package/src/metadata-builder/builders/section-field-utils.test.ts +83 -0
  140. package/src/metadata-builder/builders/section-field-utils.ts +69 -18
  141. package/src/metadata-builder/builders/section-rules/support-me.rules.ts +39 -0
  142. package/src/metadata-builder/builders/update-content-text-builder.ts +148 -0
  143. package/src/metadata-builder/builders/update-content-text-style-builder.ts +352 -0
  144. package/src/metadata-builder/helpers/rte.helpers.ts +101 -15
  145. package/src/metadata-builder/metadata-executor.ts +8 -0
  146. package/src/metadata-builder/models.ts +5 -0
  147. package/src/metadata-builder/parsers/ai-toolcall-parser.ts +31 -0
  148. package/src/metadata-builder/parsers/section-tool-arguments.ts +14 -1
  149. package/src/metadata-builder/sanitizers/rte-schema-check.ts +53 -24
  150. package/src/shared/content-settings/components/GenericTextInput.mixin.ts +1 -17
  151. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +3 -16
  152. package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.ts +4 -13
  153. package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.vue +4 -6
  154. package/src/shared/content-settings/components/text-image-field/TextImageField.vue +3 -6
  155. package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.ts +1 -6
  156. package/src/shared/content-settings/components/text-items-field/TextItemsField.vue +1 -1
  157. package/src/utils/minify-brand-page-metadata.test.ts +61 -0
  158. package/src/utils/minify-brand-page-metadata.ts +9 -4
  159. package/lib/src/brand-page/utils/migration/migration-20.d.ts +0 -2
  160. package/lib/src/brand-page/utils/migration/migration-20.js +0 -66
  161. package/lib/src/brand-page-maker/__fixtures__/complex-rte.fixture.d.ts +0 -22
  162. package/lib/src/brand-page-maker/__fixtures__/complex-rte.fixture.js +0 -22
  163. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.d.ts +0 -14
  164. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.js +0 -39
  165. package/lib/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.d.ts +0 -28
  166. package/lib/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.js +0 -90
  167. package/lib/src/brand-page-maker/utils/rte-render.util.d.ts +0 -63
  168. package/lib/src/brand-page-maker/utils/rte-render.util.js +0 -95
  169. package/lib/src/brand-page-maker/utils/rte-sanitize.util.d.ts +0 -6
  170. package/lib/src/brand-page-maker/utils/rte-sanitize.util.js +0 -158
  171. package/src/brand-page/utils/migration/migration-20.server.test.ts +0 -125
  172. package/src/brand-page/utils/migration/migration-20.test.ts +0 -72
  173. package/src/brand-page/utils/migration/migration-20.ts +0 -87
  174. package/src/brand-page/utils/text.util.test.ts +0 -47
  175. package/src/brand-page/utils/view-model.pageid-rte.test.ts +0 -104
  176. package/src/brand-page-maker/__fixtures__/complex-rte.fixture.ts +0 -23
  177. package/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.test.ts +0 -52
  178. package/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.ts +0 -42
  179. package/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.ts +0 -137
  180. package/src/brand-page-maker/utils/__snapshots__/rte-render-parity.test.ts.snap +0 -202
  181. package/src/brand-page-maker/utils/rte-features.test.ts +0 -351
  182. package/src/brand-page-maker/utils/rte-render-parity.test.ts +0 -157
  183. package/src/brand-page-maker/utils/rte-render.util.ts +0 -165
  184. package/src/brand-page-maker/utils/rte-sanitize-json.test.ts +0 -158
  185. package/src/brand-page-maker/utils/rte-sanitize.util.ts +0 -195
  186. package/src/brand-page-maker/validators/field.validator.test.ts +0 -55
@@ -30,15 +30,6 @@ import type { LogoImageModel, LogoTemplateImageModel } from './logo.model';
30
30
  import cloneDeep from 'lodash.clonedeep';
31
31
  import * as uuid from 'uuid';
32
32
  import type { BrandPagePaymentConfig } from './payment.model';
33
- import type { JSONContent } from '@tiptap/vue-3';
34
-
35
- /**
36
- * BP-5787 — a rich-text field is either a legacy inline-HTML string or a
37
- * Tiptap JSON document. Typing RTE content fields as RichTextValue (instead of
38
- * `string`) forces every consumer to handle both forms — surfacing at compile
39
- * time any code that assumes a plain string (e.g. `.replace`, `.length`).
40
- */
41
- export type RichTextValue = string | JSONContent;
42
33
 
43
34
  export * from './brand-page-context.model';
44
35
  export * from './payment.model';
@@ -289,7 +280,7 @@ export interface TextContent extends Content {
289
280
  /**
290
281
  * For BrandPage/BrandContact only
291
282
  */
292
- text: RichTextValue;
283
+ text: string;
293
284
  /**
294
285
  * For BrandSite
295
286
  */
@@ -313,9 +304,9 @@ export interface TextContent extends Content {
313
304
 
314
305
  export interface ProfileContent extends Content {
315
306
  avatarImageUrl: string;
316
- name: RichTextValue;
317
- title: RichTextValue;
318
- description: RichTextValue;
307
+ name: string;
308
+ title: string;
309
+ description: string;
319
310
  backgroundColor: BrandPageCssStyle;
320
311
  colorReplacements: ColorReplacement[];
321
312
  mediaType?: string;
@@ -336,7 +327,7 @@ export interface MapContent extends Content {
336
327
 
337
328
  export interface MailingListContent extends Content {
338
329
  acceptedFields?: 'emailOnly' | 'nameAndEmail';
339
- title: RichTextValue;
330
+ title: string;
340
331
  buttonText: string;
341
332
  titleStyle: TextStyleDeclaration;
342
333
  buttonTextStyle: TextStyleDeclaration;
@@ -396,10 +387,10 @@ export interface FormField {
396
387
  export interface ContactFormContent extends Content {
397
388
  type: 'contact-form';
398
389
  displayStyle: string;
399
- title: RichTextValue;
400
- description: RichTextValue;
390
+ title: string;
391
+ description: string;
401
392
  buttonText: string;
402
- successMessage: RichTextValue;
393
+ successMessage: string;
403
394
  fields: FormField[];
404
395
  responseEmail: string;
405
396
  imageUrl?: string;
@@ -419,8 +410,8 @@ export interface ContactFormContent extends Content {
419
410
  export interface BannerSectionContent extends Content {
420
411
  type: 'banner-section';
421
412
  imageUrl: string;
422
- title: RichTextValue;
423
- description: RichTextValue;
413
+ title: string;
414
+ description: string;
424
415
  buttonText: string | false;
425
416
  url: string;
426
417
  email?: string;
@@ -450,8 +441,8 @@ export const MEDIA_TYPES = {
450
441
  export type MediaType = keyof typeof MEDIA_TYPES;
451
442
 
452
443
  export interface TextMediaItem extends ImageItem {
453
- title: RichTextValue;
454
- paragraph: RichTextValue;
444
+ title: string;
445
+ paragraph: string;
455
446
  itemsId: number;
456
447
 
457
448
  buttonText?: string | false;
@@ -475,8 +466,8 @@ export interface TextShapeItem extends TextMediaItem {
475
466
  export interface ShapeItem extends ImageItem {
476
467
  colorReplacements: ColorReplacement[];
477
468
  mediaType: MediaType;
478
- title?: RichTextValue;
479
- paragraph?: RichTextValue;
469
+ title?: string;
470
+ paragraph?: string;
480
471
 
481
472
  // overrides for personalisation
482
473
  titleOverride?: string;
@@ -487,9 +478,9 @@ export interface TestimonialItems {
487
478
  /** Stable per-item identifier. See ImageItem.id. */
488
479
  id: string;
489
480
  imageUrl: string;
490
- name: RichTextValue;
491
- position: RichTextValue;
492
- testimonials: RichTextValue;
481
+ name: string;
482
+ position: string;
483
+ testimonials: string;
493
484
  colorReplacements: ColorReplacement[];
494
485
  mediaType: string;
495
486
  size?: string;
@@ -505,7 +496,7 @@ export interface TestimonialItems {
505
496
  export interface TextItem {
506
497
  /** Stable per-item identifier. See ImageItem.id. */
507
498
  id: string;
508
- text: RichTextValue;
499
+ text: string;
509
500
  textStyle: TextStyleDeclaration;
510
501
 
511
502
  // overrides for personalisation
@@ -527,8 +518,8 @@ export interface ImagesSectionContent extends Content, MediaSection {
527
518
  }
528
519
 
529
520
  export interface MediaSection extends Content {
530
- title: RichTextValue;
531
- description: RichTextValue;
521
+ title: string;
522
+ description: string;
532
523
  displayStyle: ImagesSectionContentDisplayStyle;
533
524
  items: TextShapeItem[] | TextMediaItem[];
534
525
  titleStyle: TextStyleDeclaration;
@@ -547,7 +538,7 @@ export interface ColorReplacement {
547
538
 
548
539
  export interface TestimonialSectionContent extends Content {
549
540
  type: 'testimonial-section';
550
- title: RichTextValue;
541
+ title: string;
551
542
  displayStyle: string;
552
543
  items: TestimonialItems[];
553
544
  titleStyle: TextStyleDeclaration;
@@ -562,8 +553,8 @@ export interface TestimonialSectionContent extends Content {
562
553
  export interface AboutSectionContent extends Content {
563
554
  type: 'about-section';
564
555
  imageUrl: string;
565
- title: RichTextValue;
566
- paragraph: RichTextValue;
556
+ title: string;
557
+ paragraph: string;
567
558
  displayStyle: string;
568
559
  titleStyle: TextStyleDeclaration;
569
560
  paragraphStyle: TextStyleDeclaration;
@@ -592,7 +583,7 @@ export type SocialLinksIconDisplayStyle =
592
583
 
593
584
  export interface SocialLinksContent extends Content {
594
585
  type: 'social-links';
595
- title: RichTextValue;
586
+ title: string;
596
587
  links: LinksItem[];
597
588
  iconDisplayStyle: SocialLinksIconDisplayStyle;
598
589
  iconFillStyles: BrandPageCssStyle;
@@ -619,8 +610,8 @@ export interface DividerSectionContent extends Content {
619
610
 
620
611
  export interface BookingSectionContent extends Content {
621
612
  type: 'booking-section';
622
- title: RichTextValue;
623
- description: RichTextValue;
613
+ title: string;
614
+ description: string;
624
615
  buttonText: string;
625
616
  url: string;
626
617
  email?: string;
@@ -462,7 +462,7 @@ exports[`migration.util > Banner Contents - text Align and Font Family should no
462
462
  },
463
463
  },
464
464
  },
465
- "v": 20,
465
+ "v": 19,
466
466
  },
467
467
  "useOldLogoRenderSize": true,
468
468
  }
@@ -914,7 +914,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
914
914
  },
915
915
  },
916
916
  },
917
- "v": 20,
917
+ "v": 19,
918
918
  },
919
919
  "useOldLogoRenderSize": true,
920
920
  }
@@ -1373,7 +1373,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
1373
1373
  },
1374
1374
  },
1375
1375
  },
1376
- "v": 20,
1376
+ "v": 19,
1377
1377
  },
1378
1378
  "useOldLogoRenderSize": true,
1379
1379
  }
@@ -22,7 +22,6 @@ import { migration16 } from './migration/migration-16';
22
22
  import { migration17 } from './migration/migration-17';
23
23
  import { migration18 } from './migration/migration-18';
24
24
  import { migration19 } from './migration/migration-19';
25
- import { migration20 } from './migration/migration-20';
26
25
 
27
26
  export interface MigrationData {
28
27
  brandPageModel: BrandPageModel;
@@ -180,17 +179,6 @@ const MIGRATION_TABLE = [
180
179
  description:
181
180
  'BP-5800: seed the button fill colour as each block’s own container colour so it is independent of the site button (existing sites render unchanged) — backgroundStyle for mailing-list, request-payment and support-me (all types); cardStyle for the BP/BC contact form (skipped on brand-site)',
182
181
  },
183
- {
184
- version: 20,
185
- migrateFn: migration20,
186
- // One-time versioned migration (NOT runAlways): legacy sites (v < 20)
187
- // convert on their first load in any environment — the maker (browser DOM)
188
- // and web-renderer SSR (migration-20 installs a jsdom window). It no longer
189
- // needs to re-run every load because the AI section builders now emit Tiptap
190
- // JSON directly, so there is no recurring post-load source of HTML to catch.
191
- description:
192
- 'BP-5787: convert inline-HTML RTE content to Tiptap JSON on first load (client or server); AI builders emit JSON directly, so this runs once per site',
193
- },
194
182
  ] as MigrationTableItem[];
195
183
 
196
184
  export const GetLatestModelVersion = () =>
@@ -87,57 +87,6 @@ describe('style.util', () => {
87
87
  );
88
88
  });
89
89
 
90
- test('applyLogoThemeToBrandPageModel preserves var() token refs in JSON RTE content (BP-5787)', () => {
91
- // Arrange — title stored as Tiptap JSON with a theme-token colour mark.
92
- const logoTheme = logoWithFlatColorsTheme;
93
- const titleDoc = {
94
- type: 'doc',
95
- content: [
96
- {
97
- type: 'heading',
98
- attrs: { level: 2, textAlign: 'center' },
99
- content: [
100
- {
101
- type: 'text',
102
- marks: [
103
- {
104
- type: 'textStyle',
105
- attrs: { color: `var(--${STYLE_THEME_KEYS.LogoTextColor})` },
106
- },
107
- ],
108
- text: 'Themed',
109
- },
110
- ],
111
- },
112
- ],
113
- };
114
- const brandPageModel = new BrandPageModel({
115
- ...BRAND_SITE,
116
- pages: [
117
- {
118
- title: '1',
119
- slug: '1',
120
- contents: [
121
- {
122
- ...createInitialBannerSectionContent(),
123
- title: titleDoc,
124
- } as any,
125
- ],
126
- },
127
- ],
128
- });
129
-
130
- // Act
131
- const { model } = applyLogoThemeToBrandPageModel(logoTheme, brandPageModel);
132
-
133
- // Assert — JSON RTE content is an object, so the var() token is NOT
134
- // flattened to rgb(); it survives so a new theme can still propagate.
135
- const title = JSON.stringify((model.pages[0].contents[0] as any).title);
136
-
137
- expect(title).toContain(`var(--${STYLE_THEME_KEYS.LogoTextColor})`);
138
- expect(title).not.toContain(logoTheme.logoTextColor.rgb);
139
- });
140
-
141
90
  test('applyLogoThemeToBrandPageModel should apply logo theme color to content color when content color has a color matched theme key', () => {
142
91
  // Arrange
143
92
  const logoTheme = logoWithFlatColorsTheme;
@@ -1,56 +1,17 @@
1
1
  import { ESCAPED_NEWLINE_CHARACTER } from '../../constants/ui';
2
2
 
3
- /**
4
- * BP-5787 — a Tiptap JSON document is an object with `type: 'doc'`.
5
- * Inlined here (rather than importing from brand-page-maker) to avoid a
6
- * circular import: rich-text-editor.util imports getRenderText from this file.
7
- */
8
- const isTiptapDoc = (value: unknown): value is { type: 'doc' } =>
9
- typeof value === 'object' &&
10
- value !== null &&
11
- (value as { type?: string }).type === 'doc';
12
-
13
- const jsonDocPlainText = (doc: unknown): string => {
14
- const parts: string[] = [];
15
-
16
- const walk = (node: any): void => {
17
- if (typeof node?.text === 'string') parts.push(node.text);
18
-
19
- node?.content?.forEach(walk);
20
- };
21
-
22
- walk(doc);
23
-
24
- return parts.join(' ').replace(/\s+/g, ' ').trim();
25
- };
26
-
27
3
  export const getRenderText = (text: string): string => {
28
- // BP-5787: RTE fields may now be Tiptap JSON objects. Non-strings pass
29
- // through untouched so the renderer (TextWrapper) handles them via its
30
- // JSON-aware path, instead of throwing on `.replace`.
31
- if (typeof text !== 'string') {
32
- return text as unknown as string;
33
- }
34
-
35
4
  return text.replace(
36
5
  new RegExp(`(${ESCAPED_NEWLINE_CHARACTER}|\\n)`, 'g'),
37
6
  '<br/>',
38
7
  );
39
8
  };
40
9
 
41
- // Accepts a legacy inline-HTML string or a Tiptap JSON document (BP-5787):
42
- // for JSON it returns the concatenated visible text; for HTML it strips tags.
43
- export const escapeContentText = (text: unknown): string | undefined => {
10
+ export const escapeContentText = (
11
+ text: string | undefined,
12
+ ): string | undefined => {
44
13
  if (!text) {
45
- return text as undefined;
46
- }
47
-
48
- if (isTiptapDoc(text)) {
49
- return jsonDocPlainText(text);
50
- }
51
-
52
- if (typeof text !== 'string') {
53
- return undefined;
14
+ return text;
54
15
  }
55
16
 
56
17
  return text
@@ -235,11 +235,9 @@ const addProfileInfo = (
235
235
  profile: ProfileViewModel,
236
236
  vcardLines: string[],
237
237
  ): void => {
238
- const name = sanitizeForVCard(getPlainTextFromRTE(profile.name) || '');
239
- const title = sanitizeForVCard(getPlainTextFromRTE(profile.title) || '');
240
- const description = sanitizeForVCard(
241
- getPlainTextFromRTE(profile.description) || '',
242
- );
238
+ const name = sanitizeForVCard(profile.name || '');
239
+ const title = sanitizeForVCard(profile.title || '');
240
+ const description = sanitizeForVCard(profile.description || '');
243
241
 
244
242
  if (name) {
245
243
  const nameParts = name.trim().split(/\s+/);
@@ -318,7 +316,7 @@ export const saveContact = (brandPageData: {
318
316
  }): void => {
319
317
  const vcard = generateVCard(brandPageData);
320
318
  const profile = findProfileContent(brandPageData);
321
- const filename = generateVCardFilename(getPlainTextFromRTE(profile?.name));
319
+ const filename = generateVCardFilename(profile?.name);
322
320
 
323
321
  downloadVCard(vcard, filename);
324
322
  };
@@ -119,7 +119,7 @@ import {
119
119
  getRouteNameByPageIndex,
120
120
  getRouteParamsByPage,
121
121
  } from './route.util';
122
- import { hasRTEContent, isTiptapDocument } from '../../brand-page-maker/utils';
122
+ import { hasRTEContent } from '../../brand-page-maker/utils';
123
123
  import {
124
124
  getPageIdFromHref,
125
125
  isHrefPageId,
@@ -1519,86 +1519,6 @@ const mapPageIdReferencesToRelativePaths = (
1519
1519
  });
1520
1520
  };
1521
1521
 
1522
- // Resolve a `pageid:<id>` internal-link href to the published relative path.
1523
- // Returns the resolved href, or null when `href` is not an internal pageid link
1524
- // (external/absolute links are left untouched). Falls back to the site root when
1525
- // the pageid can't be matched to a nav route.
1526
- const resolvePageIdHref = (
1527
- href: string,
1528
- nav: NavViewModel,
1529
- options: ViewModelMappingOptions,
1530
- ): string | null => {
1531
- // Only process internal links (no protocol, doesn't start with /)
1532
- if (!href || href.match(/^(https?:\/\/|\/)/) || !isHrefPageId(href)) {
1533
- return null;
1534
- }
1535
-
1536
- const pageId = getPageIdFromHref(href);
1537
- const route = findNavItemByPageId(nav.navItems, pageId);
1538
- const brandPageSlugRoute = options.brandPageSlug
1539
- ? `/${options.brandPageSlug}`
1540
- : '/';
1541
-
1542
- if (route) {
1543
- if (route.isRoot) {
1544
- return brandPageSlugRoute;
1545
- }
1546
-
1547
- return `${brandPageSlugRoute}${brandPageSlugRoute === '/' ? '' : '/'}${route.relativePath}`;
1548
- }
1549
-
1550
- // fallback to root if pageid cannot be resolved.
1551
- return brandPageSlugRoute;
1552
- };
1553
-
1554
- // BP-5847: walk a Tiptap JSON doc and rewrite every link mark whose href is a
1555
- // `pageid:` reference into its published relative path. Returns a NEW doc when
1556
- // something changed (so the shared model doc is never mutated), else the same
1557
- // reference.
1558
- export const resolvePageIdsInRteJson = (
1559
- doc: unknown,
1560
- nav: NavViewModel,
1561
- options: ViewModelMappingOptions,
1562
- ): unknown => {
1563
- let changed = false;
1564
-
1565
- const walk = (node: any): any => {
1566
- if (!node || typeof node !== 'object') {
1567
- return node;
1568
- }
1569
-
1570
- let next = node;
1571
-
1572
- if (Array.isArray(node.marks)) {
1573
- const marks = node.marks.map((mark: any) => {
1574
- if (mark?.type === 'link' && typeof mark.attrs?.href === 'string') {
1575
- const resolved = resolvePageIdHref(mark.attrs.href, nav, options);
1576
-
1577
- if (resolved !== null) {
1578
- changed = true;
1579
-
1580
- return { ...mark, attrs: { ...mark.attrs, href: resolved } };
1581
- }
1582
- }
1583
-
1584
- return mark;
1585
- });
1586
-
1587
- next = { ...next, marks };
1588
- }
1589
-
1590
- if (Array.isArray(node.content)) {
1591
- next = { ...next, content: node.content.map(walk) };
1592
- }
1593
-
1594
- return next;
1595
- };
1596
-
1597
- const result = walk(doc);
1598
-
1599
- return changed ? result : doc;
1600
- };
1601
-
1602
1522
  const dynamicallyMapPageIdInHyperlinksToRelativePaths = (
1603
1523
  content: any,
1604
1524
  nav: NavViewModel,
@@ -1611,15 +1531,7 @@ const dynamicallyMapPageIdInHyperlinksToRelativePaths = (
1611
1531
  return;
1612
1532
  }
1613
1533
 
1614
- if (isTiptapDocument(value)) {
1615
- // BP-5847: RTE fields may now be Tiptap JSON. Resolve pageid link marks
1616
- // here too, or internal links render as raw `pageid:` and don't navigate.
1617
- (content as unknown as Record<string, unknown>)[key] =
1618
- resolvePageIdsInRteJson(value, nav, options);
1619
- } else if (
1620
- typeof value === 'object' &&
1621
- (key === 'items' || key === 'textItems')
1622
- ) {
1534
+ if (typeof value === 'object' && (key === 'items' || key === 'textItems')) {
1623
1535
  if (Array.isArray(value)) {
1624
1536
  value.forEach((item) => {
1625
1537
  dynamicallyMapPageIdInHyperlinksToRelativePaths(item, nav, options);
@@ -1631,11 +1543,31 @@ const dynamicallyMapPageIdInHyperlinksToRelativePaths = (
1631
1543
  (content as unknown as Record<string, unknown>)[key] = value.replace(
1632
1544
  /<a\s+([^>]*?)href="([^"]*?)"([^>]*?)>/gi,
1633
1545
  (match, existingAttrsStart, href, existingAttrsEnd) => {
1634
- const resolved = resolvePageIdHref(href, nav, options);
1546
+ // Only process internal links (no protocol, doesn't start with /)
1547
+ if (href && !href.match(/^(https?:\/\/|\/)/) && isHrefPageId(href)) {
1548
+ const pageId = getPageIdFromHref(href);
1549
+
1550
+ const route = findNavItemByPageId(nav.navItems, pageId);
1551
+
1552
+ const brandPageSlugRoute = options.brandPageSlug
1553
+ ? `/${options.brandPageSlug}`
1554
+ : '/';
1555
+
1556
+ if (route) {
1557
+ let href = `${brandPageSlugRoute}`;
1558
+
1559
+ if (!route.isRoot) {
1560
+ href = `${brandPageSlugRoute}${brandPageSlugRoute === '/' ? '' : '/'}${route.relativePath}`;
1561
+ }
1562
+
1563
+ return `<a ${existingAttrsStart}href="${href}"${existingAttrsEnd}>`;
1564
+ }
1565
+
1566
+ // fallback to root if pageid cannot be resolved.
1567
+ return `<a ${existingAttrsStart}href="${brandPageSlugRoute}"${existingAttrsEnd}>`;
1568
+ }
1635
1569
 
1636
- return resolved === null
1637
- ? match
1638
- : `<a ${existingAttrsStart}href="${resolved}"${existingAttrsEnd}>`;
1570
+ return match;
1639
1571
  },
1640
1572
  );
1641
1573
  }
@@ -41,7 +41,6 @@ import type {
41
41
  BackgroundShape,
42
42
  PersonalisationRole,
43
43
  SaveContactOptions,
44
- RichTextValue,
45
44
  } from './models';
46
45
  import type { ImagesSectionContentDisplayStyle } from './constants';
47
46
 
@@ -197,8 +196,8 @@ export interface TextImageSectionViewModel {
197
196
  id: string;
198
197
  type: 'images-section';
199
198
  role: ContentType;
200
- title: RichTextValue;
201
- description: RichTextValue;
199
+ title: string;
200
+ description: string;
202
201
  displayStyle: ImagesSectionContentDisplayStyle;
203
202
  aspectRatio: AspectRatio;
204
203
  areImagesFullWidth: boolean;
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="ai-container">
2
+ <div data-component="ai-website-builder" class="ai-container">
3
3
  <div class="tw-px-5">
4
4
  <SideBarSettingsHeader
5
5
  title="AI Website Builder"
@@ -384,7 +384,7 @@
384
384
  <div class="tw-relative" :class="{ 'editor-compact': isCompact }">
385
385
  <BubbleMenu
386
386
  :editor="editor"
387
- :options="bubbleMenuOptions"
387
+ :tippy-options="tippyOptions"
388
388
  :update-delay="0"
389
389
  :should-show="shouldShow"
390
390
  class="tw-w-fit"
@@ -453,8 +453,7 @@ import {
453
453
  ButtonGroup,
454
454
  TextInput,
455
455
  } from '@designcrowd/fe-shared-lib';
456
- import { EditorContent } from '@tiptap/vue-3';
457
- import { BubbleMenu } from '@tiptap/vue-3/menus';
456
+ import { EditorContent, BubbleMenu } from '@tiptap/vue-3';
458
457
  import { useRichTextEditor } from '../../composables/rich-text-editor/useRichTextEditor';
459
458
  import FontPicker from '@shared/font-family-selector/FontPicker.vue';
460
459
  import ColorField from '@shared/content-settings/components/color-field/ColorField.vue';
@@ -952,7 +951,7 @@ const {
952
951
  hyperlinkValue,
953
952
  setHyperlinkUrlValue,
954
953
  shouldShow,
955
- bubbleMenuOptions,
954
+ tippyOptions,
956
955
  handleAdminColorChange,
957
956
  } = useRichTextEditor(
958
957
  model,
@@ -33,6 +33,7 @@ export function useAiMetadataBuilder(logger: Logger) {
33
33
  model: BrandPageModel,
34
34
  aiAssistantToolCall: AiAssistantToolCall[],
35
35
  options: {
36
+ maxCharacters?: number;
36
37
  /**
37
38
  * Invoked by the UndoBuilder to resolve the pre-prompt snapshot.
38
39
  * Required when the response includes an `undo` tool call.
@@ -513,7 +513,7 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
513
513
  message,
514
514
  websiteContext,
515
515
  websiteSnapshot: snapshotStore.snapshotBase64 || undefined,
516
- agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER,
516
+ agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER_V2,
517
517
  userPlan,
518
518
  connectionId,
519
519
  });
@@ -524,7 +524,7 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
524
524
  message,
525
525
  websiteContext,
526
526
  websiteSnapshot: snapshotStore.snapshotBase64 || undefined,
527
- agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER,
527
+ agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER_V2,
528
528
  userPlan,
529
529
  connectionId,
530
530
  },
@@ -727,11 +727,15 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
727
727
  retryCount,
728
728
  });
729
729
 
730
+ // Tool submissions must go to the SAME agent that ran the thread
731
+ // (AI QA 2026-07-05 T19: a mismatched agentType routes tool results
732
+ // to a service with no state for the thread and fails the build).
733
+ // brandSite AI is V2-only; every call site sends WEBSITE_BUILDER_V2.
730
734
  const submitResult = await client.submitToolResultsBuildAsync(
731
735
  aiThreadStore.threadId!,
732
736
  {
733
737
  toolCalls: toolResults,
734
- agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER,
738
+ agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER_V2,
735
739
  connectionId,
736
740
  retryCount,
737
741
  userPlan,
@@ -23,16 +23,20 @@ export const useBubbleMenu = (
23
23
  return false;
24
24
  };
25
25
 
26
- // v3 BubbleMenu uses Floating UI (was tippy.js in v2). Only placement + offset
27
- // carry over; the rest of the old tippy config (trigger/interactive/hideOnClick/
28
- // zIndex) is either the v3 default or handled in CSS.
29
- const bubbleMenuOptions = {
26
+ const tippyOptions = {
27
+ duration: 100,
30
28
  placement: 'bottom' as const,
31
- offset: 10,
29
+ interactive: true,
30
+ appendTo: 'parent' as const,
31
+ hideOnClick: false,
32
+ arrow: false,
33
+ offset: [0, 10] as [number, number],
34
+ trigger: 'manual' as const,
35
+ zIndex: 10,
32
36
  };
33
37
 
34
38
  return {
35
39
  shouldShow,
36
- bubbleMenuOptions,
40
+ tippyOptions,
37
41
  };
38
42
  };