@designcrowd/library.brand-page 6.1.1-json-prereq-3 → 6.1.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 (216) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-hj_ievMc.js → CreatedOnBrandCrowd-de-de-B5B5ThJ6.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-jAOSpfCw.js → CreatedOnBrandCrowd-en-us-a48CaORy.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-DZMVc-y3.js → CreatedOnBrandCrowd-es-es-xpuZ317-.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-DvB54H38.js → CreatedOnBrandCrowd-fr-ca-V-iUMArW.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-DvB54H38.js → CreatedOnBrandCrowd-fr-fr-V-iUMArW.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-bf-x1xhi.js → CreatedOnBrandCrowd-pt-br-DZ0NKSAy.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-bf-x1xhi.js → CreatedOnBrandCrowd-pt-pt-DZ0NKSAy.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-B-NY1B44.js → CreatedOnDcom-de-de-_950cgGp.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-Cd4C6KQf.js → CreatedOnDcom-en-us-DogKzH-g.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-DONlsQsm.js → CreatedOnDcom-es-es-CmGM3IPX.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-Dsv3FRpZ.js → CreatedOnDcom-fr-ca-BonEDkWZ.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-DOgyvY5C.js → CreatedOnDcom-fr-fr-DQHtKrd_.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-DX66MhJS.js → CreatedOnDcom-pt-br-CtYJSBjs.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-COe2G0bU.js → CreatedOnDcom-pt-pt-DoO9r4lA.js} +1 -1
  15. package/lib/src/brand-page/components/contact-form/ContactForm.mixin.js +7 -8
  16. package/lib/src/brand-page/components/mailing-list/MailingList.mixin.js +6 -4
  17. package/lib/src/brand-page/components/page-footer/PageFooter.mixin.d.ts +1 -0
  18. package/lib/src/brand-page/components/page-footer/PageFooter.mixin.js +4 -1
  19. package/lib/src/brand-page/components/payment/Payment.mixin.js +4 -3
  20. package/lib/src/brand-page/components/payment/__fixtures__/request-payment.d.ts +1 -0
  21. package/lib/src/brand-page/components/payment/__fixtures__/support-me.d.ts +1 -0
  22. package/lib/src/brand-page/components/payment/request-payment/RequestPayment.mixin.d.ts +1 -0
  23. package/lib/src/brand-page/components/payment/request-payment/RequestPayment.mixin.js +4 -1
  24. package/lib/src/brand-page/composables/consent.composable.d.ts +2 -0
  25. package/lib/src/brand-page/composables/consent.composable.js +9 -3
  26. package/lib/src/brand-page/models/brand-page-context.model.d.ts +7 -0
  27. package/lib/src/brand-page/models/index.d.ts +26 -34
  28. package/lib/src/brand-page/utils/context.util.d.ts +8 -0
  29. package/lib/src/brand-page/utils/context.util.js +8 -0
  30. package/lib/src/brand-page/utils/migration.util.js +0 -11
  31. package/lib/src/brand-page/utils/text.util.d.ts +1 -13
  32. package/lib/src/brand-page/utils/text.util.js +0 -64
  33. package/lib/src/brand-page/utils/vcard.util.js +4 -4
  34. package/lib/src/brand-page/utils/view-model.util.d.ts +0 -1
  35. package/lib/src/brand-page/utils/view-model.util.js +20 -68
  36. package/lib/src/brand-page/view-models.d.ts +3 -3
  37. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +1 -1
  38. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +51 -18
  39. package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.d.ts +1 -0
  40. package/lib/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.d.ts +9 -2
  41. package/lib/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.js +10 -6
  42. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontSize.d.ts +20 -0
  43. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontSize.js +44 -0
  44. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/LineHeight.d.ts +27 -0
  45. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/LineHeight.js +44 -0
  46. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +1 -1
  47. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +103 -24
  48. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +8 -0
  49. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +9 -3
  50. package/lib/src/brand-page-maker/stores/ui/ui-store.d.ts +1 -1
  51. package/lib/src/brand-page-maker/utils/index.d.ts +0 -2
  52. package/lib/src/brand-page-maker/utils/index.js +0 -2
  53. package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +5 -28
  54. package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +5 -48
  55. package/lib/src/brand-page-maker/validators/field.validator.js +2 -10
  56. package/lib/src/clients/models.d.ts +2 -0
  57. package/lib/src/css/library.brand-page-brandCrowd.min.css +99 -102
  58. package/lib/src/css/library.brand-page-brandPage.min.css +99 -102
  59. package/lib/src/css/library.brand-page-designCom.min.css +99 -102
  60. package/lib/src/css/library.brand-page-preview.min.css +99 -102
  61. package/lib/src/index.d.ts +1 -1
  62. package/lib/src/index.mjs +219 -221
  63. package/lib/src/{lib-scDtk-Pi.js → lib-DtalJKI3.js} +72445 -75920
  64. package/lib/src/lib.js +1 -2
  65. package/lib/src/metadata-builder/ai-metadata-executor.d.ts +1 -0
  66. package/lib/src/metadata-builder/ai-metadata-executor.js +19 -0
  67. package/lib/src/metadata-builder/builders/section-builders/about-section-builder.js +3 -2
  68. package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.js +3 -2
  69. package/lib/src/metadata-builder/builders/section-builders/booking-section-builder.js +3 -2
  70. package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.js +4 -3
  71. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +3 -2
  72. package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.js +2 -1
  73. package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.js +2 -1
  74. package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.js +4 -3
  75. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +3 -2
  76. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +2 -1
  77. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +11 -15
  78. package/lib/src/metadata-builder/builders/update-content-text-builder.d.ts +17 -0
  79. package/lib/src/metadata-builder/builders/update-content-text-builder.js +103 -0
  80. package/lib/src/metadata-builder/builders/update-content-text-style-builder.d.ts +16 -0
  81. package/lib/src/metadata-builder/builders/update-content-text-style-builder.js +216 -0
  82. package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +13 -11
  83. package/lib/src/metadata-builder/helpers/rte.helpers.js +73 -14
  84. package/lib/src/metadata-builder/metadata-executor.js +4 -0
  85. package/lib/src/metadata-builder/models.d.ts +2 -0
  86. package/lib/src/metadata-builder/models.js +2 -0
  87. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +19 -0
  88. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.js +4 -0
  89. package/lib/src/metadata-builder/sanitizers/rte-schema-check.d.ts +8 -7
  90. package/lib/src/metadata-builder/sanitizers/rte-schema-check.js +52 -21
  91. package/lib/src/shared/content-settings/components/GenericTextInput.mixin.d.ts +1 -1
  92. package/lib/src/shared/content-settings/components/GenericTextInput.mixin.js +10 -35
  93. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +1 -1
  94. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +3 -12
  95. package/lib/src/shared/content-settings/components/email-field/EmailField.mixin.d.ts +1 -1
  96. package/lib/src/shared/content-settings/components/tel-field/TelField.mixin.d.ts +1 -1
  97. package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.d.ts +2 -3
  98. package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.js +3 -10
  99. package/lib/src/shared/content-settings/components/text-field/TextField.mixin.d.ts +1 -1
  100. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.d.ts +1 -2
  101. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.js +1 -4
  102. package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +1 -1
  103. package/lib/src/shared/content-settings/components/url-field/UrlField.mixin.d.ts +1 -1
  104. package/lib/src/shared/content-settings/components/youtube-video-field/YoutubeVideoField.mixin.d.ts +1 -1
  105. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +1 -1
  106. package/lib/src/shared/logo-versions/LogoVersions.mixin.d.ts +1 -1
  107. package/lib/src/shared/my-designs/MyDesigns.mixin.d.ts +1 -1
  108. package/lib/src/shared/my-uploads/MyMedia.mixin.d.ts +1 -1
  109. package/lib/src/shared/my-uploads/MyUploads.mixin.d.ts +1 -1
  110. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +1 -1
  111. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +1 -1
  112. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +1 -1
  113. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +1 -1
  114. package/lib/src/shared/template-settings/store/template-settings-store.d.ts +2 -0
  115. package/lib/src/shared/template-settings/store/template-settings-store.js +72 -24
  116. package/lib/src/shared/unsplash-library/UnsplashLibrary.mixin.d.ts +1 -1
  117. package/lib/src/utils/minify-brand-page-metadata.js +1 -4
  118. package/package.json +15 -17
  119. package/src/brand-page/components/contact-form/ContactForm.mixin.ts +9 -7
  120. package/src/brand-page/components/cookie-consent/CookieConsent.vue +1 -0
  121. package/src/brand-page/components/mailing-list/MailingList.mixin.ts +8 -3
  122. package/src/brand-page/components/navigation/navigation-carousel/NavigationCarousel.vue +5 -1
  123. package/src/brand-page/components/page-footer/PageFooter.mixin.ts +4 -1
  124. package/src/brand-page/components/page-footer/PageFooter.vue +1 -1
  125. package/src/brand-page/components/payment/Payment.mixin.ts +4 -3
  126. package/src/brand-page/components/payment/request-payment/RequestPayment.mixin.ts +8 -1
  127. package/src/brand-page/components/payment/request-payment/RequestPayment.vue +1 -1
  128. package/src/brand-page/components/save-contact/SaveContactWidget.vue +2 -1
  129. package/src/brand-page/components/shop/Shop.vue +6 -3
  130. package/src/brand-page/components/social-links/SocialLinks.vue +5 -2
  131. package/src/brand-page/components/text-wrapper/TextWrapper.vue +6 -17
  132. package/src/brand-page/composables/consent.composable.ts +18 -4
  133. package/src/brand-page/models/brand-page-context.model.ts +7 -0
  134. package/src/brand-page/models/index.ts +26 -35
  135. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -3
  136. package/src/brand-page/utils/context.util.test.ts +43 -0
  137. package/src/brand-page/utils/context.util.ts +10 -0
  138. package/src/brand-page/utils/migration.util.ts +0 -12
  139. package/src/brand-page/utils/style.util.test.ts +0 -51
  140. package/src/brand-page/utils/text.util.ts +4 -83
  141. package/src/brand-page/utils/vcard.util.ts +4 -6
  142. package/src/brand-page/utils/view-model.util.ts +26 -94
  143. package/src/brand-page/view-models.ts +2 -3
  144. package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +4 -5
  145. package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.test.ts +135 -0
  146. package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +62 -21
  147. package/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.ts +1 -0
  148. package/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.ts +10 -6
  149. package/src/brand-page-maker/composables/rich-text-editor/extensions/FontSize.ts +73 -0
  150. package/src/brand-page-maker/composables/rich-text-editor/extensions/LineHeight.ts +85 -0
  151. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +111 -27
  152. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +9 -0
  153. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +11 -3
  154. package/src/brand-page-maker/stores/ui/ui-store.ts +1 -1
  155. package/src/brand-page-maker/utils/index.ts +0 -2
  156. package/src/brand-page-maker/utils/rich-text-editor.util.test.ts +3 -37
  157. package/src/brand-page-maker/utils/rich-text-editor.util.ts +11 -66
  158. package/src/brand-page-maker/validators/field.validator.ts +2 -10
  159. package/src/clients/models.ts +3 -0
  160. package/src/lib.ts +1 -9
  161. package/src/metadata-builder/ai-metadata-executor.ts +26 -0
  162. package/src/metadata-builder/builders/section-builders/about-section-builder.ts +3 -2
  163. package/src/metadata-builder/builders/section-builders/banner-section-builder.ts +3 -2
  164. package/src/metadata-builder/builders/section-builders/booking-section-builder.ts +5 -2
  165. package/src/metadata-builder/builders/section-builders/contact-form-builder.ts +4 -3
  166. package/src/metadata-builder/builders/section-builders/images-section-builder.ts +3 -2
  167. package/src/metadata-builder/builders/section-builders/mailing-list-builder.ts +2 -1
  168. package/src/metadata-builder/builders/section-builders/mailing-list-section-builder.ts +2 -1
  169. package/src/metadata-builder/builders/section-builders/profile-section-builder.ts +6 -3
  170. package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +3 -2
  171. package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +2 -1
  172. package/src/metadata-builder/builders/section-builders/text-section-builder.ts +13 -19
  173. package/src/metadata-builder/builders/update-content-text-builder.ts +148 -0
  174. package/src/metadata-builder/builders/update-content-text-style-builder.ts +352 -0
  175. package/src/metadata-builder/helpers/rte.helpers.ts +101 -15
  176. package/src/metadata-builder/metadata-executor.ts +5 -0
  177. package/src/metadata-builder/models.ts +3 -0
  178. package/src/metadata-builder/parsers/ai-toolcall-parser.ts +27 -0
  179. package/src/metadata-builder/sanitizers/rte-schema-check.ts +53 -24
  180. package/src/shared/content-settings/components/GenericTextInput.mixin.ts +11 -42
  181. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +3 -16
  182. package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.ts +4 -13
  183. package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.vue +4 -6
  184. package/src/shared/content-settings/components/text-image-field/TextImageField.vue +3 -6
  185. package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.ts +1 -6
  186. package/src/shared/content-settings/components/text-items-field/TextItemsField.vue +1 -1
  187. package/src/shared/template-settings/store/template-settings-store.ts +93 -27
  188. package/src/utils/minify-brand-page-metadata.ts +1 -4
  189. package/lib/src/brand-page/utils/migration/migration-20.d.ts +0 -2
  190. package/lib/src/brand-page/utils/migration/migration-20.js +0 -66
  191. package/lib/src/brand-page-maker/__fixtures__/complex-rte.fixture.d.ts +0 -22
  192. package/lib/src/brand-page-maker/__fixtures__/complex-rte.fixture.js +0 -22
  193. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.d.ts +0 -14
  194. package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.js +0 -39
  195. package/lib/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.d.ts +0 -28
  196. package/lib/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.js +0 -117
  197. package/lib/src/brand-page-maker/utils/rte-render.util.d.ts +0 -63
  198. package/lib/src/brand-page-maker/utils/rte-render.util.js +0 -95
  199. package/lib/src/brand-page-maker/utils/rte-sanitize.util.d.ts +0 -6
  200. package/lib/src/brand-page-maker/utils/rte-sanitize.util.js +0 -156
  201. package/src/brand-page/utils/migration/migration-20.server.test.ts +0 -125
  202. package/src/brand-page/utils/migration/migration-20.test.ts +0 -72
  203. package/src/brand-page/utils/migration/migration-20.ts +0 -87
  204. package/src/brand-page/utils/text.util.test.ts +0 -106
  205. package/src/brand-page/utils/view-model.pageid-rte.test.ts +0 -104
  206. package/src/brand-page-maker/__fixtures__/complex-rte.fixture.ts +0 -23
  207. package/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.test.ts +0 -52
  208. package/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.ts +0 -42
  209. package/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.ts +0 -162
  210. package/src/brand-page-maker/utils/__snapshots__/rte-render-parity.test.ts.snap +0 -202
  211. package/src/brand-page-maker/utils/rte-features.test.ts +0 -378
  212. package/src/brand-page-maker/utils/rte-render-parity.test.ts +0 -164
  213. package/src/brand-page-maker/utils/rte-render.util.ts +0 -165
  214. package/src/brand-page-maker/utils/rte-sanitize-json.test.ts +0 -172
  215. package/src/brand-page-maker/utils/rte-sanitize.util.ts +0 -192
  216. package/src/brand-page-maker/validators/field.validator.test.ts +0 -55
@@ -1,79 +1,15 @@
1
1
  import { ESCAPED_NEWLINE_CHARACTER } from '../../constants/ui';
2
- /**
3
- * BP-5787 — a Tiptap JSON document is an object with `type: 'doc'`.
4
- * Inlined here (rather than importing from brand-page-maker) to avoid a
5
- * circular import: rich-text-editor.util imports getRenderText from this file.
6
- */
7
- const isTiptapDoc = (value) => typeof value === 'object' &&
8
- value !== null &&
9
- value.type === 'doc';
10
- const jsonDocPlainText = (doc) => {
11
- const parts = [];
12
- const walk = (node) => {
13
- if (typeof node?.text === 'string')
14
- parts.push(node.text);
15
- node?.content?.forEach(walk);
16
- };
17
- walk(doc);
18
- return parts.join(' ').replace(/\s+/g, ' ').trim();
19
- };
20
2
  export const getRenderText = (text) => {
21
- // BP-5787: RTE fields may now be Tiptap JSON objects. Non-strings pass
22
- // through untouched so the renderer (TextWrapper) handles them via its
23
- // JSON-aware path, instead of throwing on `.replace`.
24
- if (typeof text !== 'string') {
25
- return text;
26
- }
27
3
  return text.replace(new RegExp(`(${ESCAPED_NEWLINE_CHARACTER}|\\n)`, 'g'), '<br/>');
28
4
  };
29
- // Accepts a legacy inline-HTML string or a Tiptap JSON document (BP-5787):
30
- // for JSON it returns the concatenated visible text; for HTML it strips tags.
31
5
  export const escapeContentText = (text) => {
32
6
  if (!text) {
33
7
  return text;
34
8
  }
35
- if (isTiptapDoc(text)) {
36
- return jsonDocPlainText(text);
37
- }
38
- if (typeof text !== 'string') {
39
- return undefined;
40
- }
41
9
  return text
42
10
  .replace(/(<([^>]+)>)/gi, '')
43
11
  .replace(/(\r\n|\r|\n)/g, ESCAPED_NEWLINE_CHARACTER);
44
12
  };
45
- /**
46
- * Character length of RTE content as the *editor* counts it — ProseMirror
47
- * `doc.textContent`: text nodes concatenated with NO separator. This is the
48
- * metric the MaxLength extension gates on, so length indicators must use it too.
49
- *
50
- * Do NOT use escapeContentText/jsonDocPlainText for length limiting: those
51
- * join text nodes with a space for readable plain-text extraction, so they
52
- * over-count by one character per inline mark boundary. Converting a word to a
53
- * hyperlink (or bolding it, etc.) splits its text node, making the counter
54
- * report length+1 for content the editor considers exactly at the cap (BP-5787).
55
- */
56
- export const getContentTextLength = (value) => {
57
- if (!value) {
58
- return 0;
59
- }
60
- if (isTiptapDoc(value)) {
61
- let length = 0;
62
- const walk = (node) => {
63
- if (typeof node?.text === 'string') {
64
- length += node.text.length;
65
- }
66
- node?.content?.forEach(walk);
67
- };
68
- walk(value);
69
- return length;
70
- }
71
- if (typeof value !== 'string') {
72
- return 0;
73
- }
74
- // Legacy inline-HTML string: count visible text with tags stripped.
75
- return value.replace(/(<([^>]+)>)/gi, '').length;
76
- };
77
13
  export const decodeHtmlEntities = (text) => {
78
14
  return text
79
15
  .replace(/&lt;/g, '<')
@@ -150,9 +150,9 @@ const processSocialLinks = (socialLinksContent, vcardLines, addedEntries) => {
150
150
  });
151
151
  };
152
152
  const addProfileInfo = (profile, vcardLines) => {
153
- const name = sanitizeForVCard(getPlainTextFromRTE(profile.name) || '');
154
- const title = sanitizeForVCard(getPlainTextFromRTE(profile.title) || '');
155
- const description = sanitizeForVCard(getPlainTextFromRTE(profile.description) || '');
153
+ const name = sanitizeForVCard(profile.name || '');
154
+ const title = sanitizeForVCard(profile.title || '');
155
+ const description = sanitizeForVCard(profile.description || '');
156
156
  if (name) {
157
157
  const nameParts = name.trim().split(/\s+/);
158
158
  const lastName = nameParts.length > 1 ? nameParts.pop() || '' : '';
@@ -205,6 +205,6 @@ const downloadVCard = (vcard, filename) => {
205
205
  export const saveContact = (brandPageData) => {
206
206
  const vcard = generateVCard(brandPageData);
207
207
  const profile = findProfileContent(brandPageData);
208
- const filename = generateVCardFilename(getPlainTextFromRTE(profile?.name));
208
+ const filename = generateVCardFilename(profile?.name);
209
209
  downloadVCard(vcard, filename);
210
210
  };
@@ -28,7 +28,6 @@ interface ViewModelMappingOptions {
28
28
  setVideoUrlsWithToken?: (token: string, videoUrl: string, previewImageUrl: string, assetId: string) => void;
29
29
  }
30
30
  export declare const getBrandPageViewModelFromBrandPageModel: (model: BrandPageModel, brandPageToken: string | undefined, showBrandCrowdLogo: boolean | undefined, options: ViewModelMappingOptions) => BrandPageViewModel;
31
- export declare const resolvePageIdsInRteJson: (doc: unknown, nav: NavViewModel, options: ViewModelMappingOptions) => unknown;
32
31
  export declare const isLogoViewModel: (viewModel: ContentViewModel) => viewModel is LogoViewModel;
33
32
  /** for service.brand-page website preview by logo draft token */
34
33
  export declare const applyLogoImageToBrandPageViewModel: (viewModel: BrandPageViewModel, logoImage: LogoImageModel) => BrandPageViewModel;
@@ -10,7 +10,7 @@ import { isValidSvgUrl } from './image.util';
10
10
  import { isLogoContent } from './model.util';
11
11
  import { getBoxShadowValue } from './button.util';
12
12
  import { findNavItemByPageId, getRouteNameByPageIndex, getRouteParamsByPage, } from './route.util';
13
- import { hasRTEContent, isTiptapDocument } from '../../brand-page-maker/utils';
13
+ import { hasRTEContent } from '../../brand-page-maker/utils';
14
14
  import { getPageIdFromHref, isHrefPageId, } from '../../brand-page-maker/composables/rich-text-editor/hyperlink';
15
15
  const BUTTON_BORDER_RADIUS = '9999px';
16
16
  const CONTENT_BORDER_RADIUS = '48px';
@@ -864,75 +864,13 @@ const mapPageIdReferencesToRelativePaths = (pages, nav, options) => {
864
864
  });
865
865
  });
866
866
  };
867
- // Resolve a `pageid:<id>` internal-link href to the published relative path.
868
- // Returns the resolved href, or null when `href` is not an internal pageid link
869
- // (external/absolute links are left untouched). Falls back to the site root when
870
- // the pageid can't be matched to a nav route.
871
- const resolvePageIdHref = (href, nav, options) => {
872
- // Only process internal links (no protocol, doesn't start with /)
873
- if (!href || href.match(/^(https?:\/\/|\/)/) || !isHrefPageId(href)) {
874
- return null;
875
- }
876
- const pageId = getPageIdFromHref(href);
877
- const route = findNavItemByPageId(nav.navItems, pageId);
878
- const brandPageSlugRoute = options.brandPageSlug
879
- ? `/${options.brandPageSlug}`
880
- : '/';
881
- if (route) {
882
- if (route.isRoot) {
883
- return brandPageSlugRoute;
884
- }
885
- return `${brandPageSlugRoute}${brandPageSlugRoute === '/' ? '' : '/'}${route.relativePath}`;
886
- }
887
- // fallback to root if pageid cannot be resolved.
888
- return brandPageSlugRoute;
889
- };
890
- // BP-5847: walk a Tiptap JSON doc and rewrite every link mark whose href is a
891
- // `pageid:` reference into its published relative path. Returns a NEW doc when
892
- // something changed (so the shared model doc is never mutated), else the same
893
- // reference.
894
- export const resolvePageIdsInRteJson = (doc, nav, options) => {
895
- let changed = false;
896
- const walk = (node) => {
897
- if (!node || typeof node !== 'object') {
898
- return node;
899
- }
900
- let next = node;
901
- if (Array.isArray(node.marks)) {
902
- const marks = node.marks.map((mark) => {
903
- if (mark?.type === 'link' && typeof mark.attrs?.href === 'string') {
904
- const resolved = resolvePageIdHref(mark.attrs.href, nav, options);
905
- if (resolved !== null) {
906
- changed = true;
907
- return { ...mark, attrs: { ...mark.attrs, href: resolved } };
908
- }
909
- }
910
- return mark;
911
- });
912
- next = { ...next, marks };
913
- }
914
- if (Array.isArray(node.content)) {
915
- next = { ...next, content: node.content.map(walk) };
916
- }
917
- return next;
918
- };
919
- const result = walk(doc);
920
- return changed ? result : doc;
921
- };
922
867
  const dynamicallyMapPageIdInHyperlinksToRelativePaths = (content, nav, options) => {
923
868
  Object.keys(content).forEach((key) => {
924
869
  const value = content[key];
925
870
  if (value === undefined || value === null) {
926
871
  return;
927
872
  }
928
- if (isTiptapDocument(value)) {
929
- // BP-5847: RTE fields may now be Tiptap JSON. Resolve pageid link marks
930
- // here too, or internal links render as raw `pageid:` and don't navigate.
931
- content[key] =
932
- resolvePageIdsInRteJson(value, nav, options);
933
- }
934
- else if (typeof value === 'object' &&
935
- (key === 'items' || key === 'textItems')) {
873
+ if (typeof value === 'object' && (key === 'items' || key === 'textItems')) {
936
874
  if (Array.isArray(value)) {
937
875
  value.forEach((item) => {
938
876
  dynamicallyMapPageIdInHyperlinksToRelativePaths(item, nav, options);
@@ -944,10 +882,24 @@ const dynamicallyMapPageIdInHyperlinksToRelativePaths = (content, nav, options)
944
882
  }
945
883
  else if (typeof value === 'string' && hasRTEContent(value)) {
946
884
  content[key] = value.replace(/<a\s+([^>]*?)href="([^"]*?)"([^>]*?)>/gi, (match, existingAttrsStart, href, existingAttrsEnd) => {
947
- const resolved = resolvePageIdHref(href, nav, options);
948
- return resolved === null
949
- ? match
950
- : `<a ${existingAttrsStart}href="${resolved}"${existingAttrsEnd}>`;
885
+ // Only process internal links (no protocol, doesn't start with /)
886
+ if (href && !href.match(/^(https?:\/\/|\/)/) && isHrefPageId(href)) {
887
+ const pageId = getPageIdFromHref(href);
888
+ const route = findNavItemByPageId(nav.navItems, pageId);
889
+ const brandPageSlugRoute = options.brandPageSlug
890
+ ? `/${options.brandPageSlug}`
891
+ : '/';
892
+ if (route) {
893
+ let href = `${brandPageSlugRoute}`;
894
+ if (!route.isRoot) {
895
+ href = `${brandPageSlugRoute}${brandPageSlugRoute === '/' ? '' : '/'}${route.relativePath}`;
896
+ }
897
+ return `<a ${existingAttrsStart}href="${href}"${existingAttrsEnd}>`;
898
+ }
899
+ // fallback to root if pageid cannot be resolved.
900
+ return `<a ${existingAttrsStart}href="${brandPageSlugRoute}"${existingAttrsEnd}>`;
901
+ }
902
+ return match;
951
903
  });
952
904
  }
953
905
  });
@@ -1,4 +1,4 @@
1
- import type { ButtonWithModalContent, ProfileContent, TextContent, VideoContent, ImageContent, ContentType, ButtonStyles, LogoStyles, MapContent, ImageGalleryContent, GalleryStyles, MailingListContent, RequestPaymentContent, ShopContent, SupportMeContent, ContactFormContent, BannerSectionContent, BrandPageType, SocialLinksContent, TestimonialSectionContent, AboutSectionContent, DividerSectionContent, ShapesSectionContent, ButtonLinkType, PageHeaderMobile, PageHeaderDesktop, PageFooterMobile, PageFooterDesktop, TextMediaItem, TextShapeItem, TextStyleDeclaration, AspectRatio, LogoImageModel, LogoTemplateImageModel, CookieOptions, BookingSectionContent, MediaTypes, TextStyles, BackgroundStyle, BackgroundShape, PersonalisationRole, SaveContactOptions, RichTextValue } from './models';
1
+ import type { ButtonWithModalContent, ProfileContent, TextContent, VideoContent, ImageContent, ContentType, ButtonStyles, LogoStyles, MapContent, ImageGalleryContent, GalleryStyles, MailingListContent, RequestPaymentContent, ShopContent, SupportMeContent, ContactFormContent, BannerSectionContent, BrandPageType, SocialLinksContent, TestimonialSectionContent, AboutSectionContent, DividerSectionContent, ShapesSectionContent, ButtonLinkType, PageHeaderMobile, PageHeaderDesktop, PageFooterMobile, PageFooterDesktop, TextMediaItem, TextShapeItem, TextStyleDeclaration, AspectRatio, LogoImageModel, LogoTemplateImageModel, CookieOptions, BookingSectionContent, MediaTypes, TextStyles, BackgroundStyle, BackgroundShape, PersonalisationRole, SaveContactOptions } from './models';
2
2
  import type { ImagesSectionContentDisplayStyle } from './constants';
3
3
  export type ViewModelType = 'button' | 'image' | 'image-gallery' | 'logo' | 'map' | 'mailing-list' | 'profile' | 'support-me' | 'request-payment' | 'text' | 'video' | 'contact-form' | 'banner-section' | 'images-section' | 'about-section' | 'divider-section' | 'testimonial-section' | 'social-links' | 'shapes-section' | 'shop-section' | 'booking-section';
4
4
  export interface ContentViewModel {
@@ -94,8 +94,8 @@ export interface TextImageSectionViewModel {
94
94
  id: string;
95
95
  type: 'images-section';
96
96
  role: ContentType;
97
- title: RichTextValue;
98
- description: RichTextValue;
97
+ title: string;
98
+ description: string;
99
99
  displayStyle: ImagesSectionContentDisplayStyle;
100
100
  aspectRatio: AspectRatio;
101
101
  areImagesFullWidth: boolean;
@@ -952,7 +952,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
952
952
  mode: import("@shared/models").UiScreenSizeMode;
953
953
  }): void;
954
954
  setUserPersonalisationData({ personalisationData, }: {
955
- personalisationData: UserPersonalisationContent[];
955
+ personalisationData: UserPersonalisationContent[] | undefined;
956
956
  }): void;
957
957
  setUserPromptContentKey({ userPromptContentKey, }: {
958
958
  userPromptContentKey: string | undefined;
@@ -8,6 +8,20 @@ import { useBrandPageContainerStore, useBrandPageMakerStore, useBrandPageMakerUs
8
8
  import { useUiTemplateSettingsStore } from '@shared/template-settings/store';
9
9
  import { applyLogoImageBase64UrlToBrandPageTemplateModel, applyLogoImageToBrandPageTemplateModel, applyLogoTemplateImageToBrandPageTemplateModel, } from '@brand-page/utils/logo.util';
10
10
  import { useVideoStore } from '@src/lib';
11
+ // Content params the backend may bake into a preview URL. When the editor's key wins,
12
+ // none of these may survive — a stale one alongside the new key is the bp-5941 mismatch.
13
+ // contentKey MUST stay listed: preview-renderer prefers contentKey+userToken over
14
+ // userPromptContentKey, so a surviving contentKey would silently win. userToken alone
15
+ // can't trigger that branch, so it's left as the backend sent it.
16
+ const BAKED_CONTENT_PARAMS = ['contentKey', 'userPromptContentKey'];
17
+ const toUrl = (value) => {
18
+ try {
19
+ return new URL(value);
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ };
11
25
  const DEBOUNCE_IN_MS = 250;
12
26
  export default defineComponent({
13
27
  emits: ['template-selected'],
@@ -169,25 +183,44 @@ export default defineComponent({
169
183
  if (!previewImageUrl) {
170
184
  return '';
171
185
  }
172
- const isAlreadyPersonalised = previewImageUrl.includes('contentKey=') ||
173
- previewImageUrl.includes('userPromptContentKey=');
174
- if (this.isPersonalisable &&
175
- this.template.contentKey &&
176
- !isAlreadyPersonalised) {
177
- if (this.userToken && !this.template.usesUserPromptContentKey) {
178
- previewImageUrl += `&contentKey=${this.template.contentKey}`;
179
- // The backend already bakes userToken into brand-site preview URLs. Only add
180
- // it when missing - two userToken params parse as an array and the preview
181
- // renderer rejects it ("userToken must be a string type") (bp-5765).
182
- if (!previewImageUrl.includes('userToken=')) {
183
- previewImageUrl += `&userToken=${this.userToken}`;
184
- }
186
+ const hasAuthoritativeUserPromptKey = this.isPersonalisable &&
187
+ this.template.usesUserPromptContentKey &&
188
+ !!this.template.contentKey;
189
+ if (hasAuthoritativeUserPromptKey) {
190
+ // The editor resolves post-purchase content from the current industry, so its
191
+ // userPrompt key is authoritative. On empty search the backend bakes a per-template
192
+ // logo-draft contentKey (DY-1305) that diverges from the editor (bp-5941); strip any
193
+ // baked content params and resolve from the userPrompt S3 bucket via the editor's key.
194
+ const url = toUrl(previewImageUrl);
195
+ // Not a parseable absolute URL — nothing to personalise, leave it alone.
196
+ if (!url) {
197
+ return previewImageUrl;
185
198
  }
186
- else {
187
- // userPromptContentKey resolves from the userPrompt S3 bucket (real AI images).
188
- // Post-purchase designs with a userPrompt key route here too, NOT through the
189
- // userToken/regular-bucket branch above which holds placeholders (bp-5454).
190
- previewImageUrl += `&userPromptContentKey=${this.template.contentKey}`;
199
+ BAKED_CONTENT_PARAMS.forEach((param) => url.searchParams.delete(param));
200
+ url.searchParams.set('userPromptContentKey', this.template.contentKey);
201
+ previewImageUrl = url.toString();
202
+ }
203
+ else {
204
+ const isAlreadyPersonalised = previewImageUrl.includes('contentKey=') ||
205
+ previewImageUrl.includes('userPromptContentKey=');
206
+ if (this.isPersonalisable &&
207
+ this.template.contentKey &&
208
+ !isAlreadyPersonalised) {
209
+ if (this.userToken) {
210
+ previewImageUrl += `&contentKey=${this.template.contentKey}`;
211
+ // The backend already bakes userToken into brand-site preview URLs. Only add
212
+ // it when missing - two userToken params parse as an array and the preview
213
+ // renderer rejects it ("userToken must be a string type") (bp-5765).
214
+ if (!previewImageUrl.includes('userToken=')) {
215
+ previewImageUrl += `&userToken=${this.userToken}`;
216
+ }
217
+ }
218
+ else {
219
+ // userPromptContentKey resolves from the userPrompt S3 bucket (real AI images).
220
+ // Post-purchase designs with a userPrompt key route here too, NOT through the
221
+ // userToken/regular-bucket branch above which holds placeholders (bp-5454).
222
+ previewImageUrl += `&userPromptContentKey=${this.template.contentKey}`;
223
+ }
191
224
  }
192
225
  }
193
226
  if (this.logoImage?.logoVariation !== undefined) {
@@ -21,6 +21,7 @@ export interface AiMetadataBuilderResult {
21
21
  }
22
22
  export declare function useAiMetadataBuilder(logger: Logger): {
23
23
  applyAiToolCallsAsync: (model: BrandPageModel, aiAssistantToolCall: AiAssistantToolCall[], options?: {
24
+ maxCharacters?: number;
24
25
  /**
25
26
  * Invoked by the UndoBuilder to resolve the pre-prompt snapshot.
26
27
  * Required when the response includes an `undo` tool call.
@@ -5,8 +5,15 @@ export declare const useBubbleMenu: (editor: Editor, isHyperlinkPopupOpen?: Ref<
5
5
  editor: any;
6
6
  state: any;
7
7
  }) => any;
8
- bubbleMenuOptions: {
8
+ tippyOptions: {
9
+ duration: number;
9
10
  placement: "bottom";
10
- offset: number;
11
+ interactive: boolean;
12
+ appendTo: "parent";
13
+ hideOnClick: boolean;
14
+ arrow: boolean;
15
+ offset: [number, number];
16
+ trigger: "manual";
17
+ zIndex: number;
11
18
  };
12
19
  };
@@ -13,15 +13,19 @@ export const useBubbleMenu = (editor, isHyperlinkPopupOpen) => {
13
13
  }
14
14
  return false;
15
15
  };
16
- // v3 BubbleMenu uses Floating UI (was tippy.js in v2). Only placement + offset
17
- // carry over; the rest of the old tippy config (trigger/interactive/hideOnClick/
18
- // zIndex) is either the v3 default or handled in CSS.
19
- const bubbleMenuOptions = {
16
+ const tippyOptions = {
17
+ duration: 100,
20
18
  placement: 'bottom',
21
- offset: 10,
19
+ interactive: true,
20
+ appendTo: 'parent',
21
+ hideOnClick: false,
22
+ arrow: false,
23
+ offset: [0, 10],
24
+ trigger: 'manual',
25
+ zIndex: 10,
22
26
  };
23
27
  return {
24
28
  shouldShow,
25
- bubbleMenuOptions,
29
+ tippyOptions,
26
30
  };
27
31
  };
@@ -0,0 +1,20 @@
1
+ import { Extension } from '@tiptap/core';
2
+ import '@tiptap/extension-text-style';
3
+ export type FontSizeOptions = {
4
+ types: string[];
5
+ };
6
+ declare module '@tiptap/core' {
7
+ interface Commands<ReturnType> {
8
+ fontSize: {
9
+ /**
10
+ * Set the font size
11
+ */
12
+ setFontSize: (fontSize: string) => ReturnType;
13
+ /**
14
+ * Unset the font size
15
+ */
16
+ unsetFontSize: () => ReturnType;
17
+ };
18
+ }
19
+ }
20
+ export declare const FontSize: Extension<FontSizeOptions, any>;
@@ -0,0 +1,44 @@
1
+ import { Extension } from '@tiptap/core';
2
+ import '@tiptap/extension-text-style';
3
+ export const FontSize = Extension.create({
4
+ name: 'fontSize',
5
+ addOptions() {
6
+ return {
7
+ types: ['textStyle'],
8
+ };
9
+ },
10
+ addGlobalAttributes() {
11
+ return [
12
+ {
13
+ types: this.options.types,
14
+ attributes: {
15
+ fontSize: {
16
+ default: null,
17
+ parseHTML: (element) => element.style.fontSize.replace(/['"]+/g, ''),
18
+ renderHTML: (attributes) => {
19
+ if (!attributes.fontSize) {
20
+ return {};
21
+ }
22
+ return {
23
+ style: `font-size: ${attributes.fontSize}`,
24
+ };
25
+ },
26
+ },
27
+ },
28
+ },
29
+ ];
30
+ },
31
+ addCommands() {
32
+ return {
33
+ setFontSize: (fontSize) => ({ chain }) => {
34
+ return chain().setMark('textStyle', { fontSize }).run();
35
+ },
36
+ unsetFontSize: () => ({ chain }) => {
37
+ return chain()
38
+ .setMark('textStyle', { fontSize: null })
39
+ .removeEmptyTextStyle()
40
+ .run();
41
+ },
42
+ };
43
+ },
44
+ });
@@ -0,0 +1,27 @@
1
+ import { Extension } from '@tiptap/core';
2
+ export type LineHeightOptions = {
3
+ /**
4
+ * Node / mark types that should carry the `lineHeight` attribute.
5
+ * Defaults to `['textStyle']` to piggy‑back on TipTap’s built‑in mark.
6
+ */
7
+ types: string[];
8
+ };
9
+ declare module '@tiptap/core' {
10
+ interface Commands<ReturnType> {
11
+ lineHeight: {
12
+ /**
13
+ * Apply a line‑height to the current selection (or stored marks).
14
+ */
15
+ setLineHeight: (heightValue: string) => ReturnType;
16
+ /**
17
+ * Remove any line‑height attribute.
18
+ */
19
+ unsetLineHeight: () => ReturnType;
20
+ /**
21
+ * Read the current line‑height from the selection / stored marks.
22
+ */
23
+ getLineHeight: () => ReturnType;
24
+ };
25
+ }
26
+ }
27
+ export declare const LineHeight: Extension<LineHeightOptions, any>;
@@ -0,0 +1,44 @@
1
+ import { Extension } from '@tiptap/core';
2
+ export const LineHeight = Extension.create({
3
+ name: 'lineHeight',
4
+ addOptions() {
5
+ return {
6
+ types: ['textStyle'],
7
+ };
8
+ },
9
+ addGlobalAttributes() {
10
+ return [
11
+ {
12
+ types: this.options.types,
13
+ attributes: {
14
+ lineHeight: {
15
+ default: null,
16
+ parseHTML: (element) => (element.style.lineHeight || '').replace(/['"]+/g, ''),
17
+ renderHTML: (attributes) => {
18
+ if (!attributes.lineHeight) {
19
+ return {};
20
+ }
21
+ return { style: `line-height: ${attributes.lineHeight}` };
22
+ },
23
+ },
24
+ },
25
+ },
26
+ ];
27
+ },
28
+ addCommands() {
29
+ return {
30
+ setLineHeight: (lineHeight) => ({ chain }) => {
31
+ return chain().setMark('textStyle', { lineHeight }).run();
32
+ },
33
+ unsetLineHeight: () => ({ chain }) => {
34
+ return chain()
35
+ .setMark('textStyle', { lineHeight: null })
36
+ .removeEmptyTextStyle()
37
+ .run();
38
+ },
39
+ getLineHeight: () => ({ editor }) => {
40
+ return editor.getAttributes('textStyle').lineHeight;
41
+ },
42
+ };
43
+ },
44
+ });
@@ -43,7 +43,7 @@ interface UseRichTextEditorReturn {
43
43
  editor: any;
44
44
  state: any;
45
45
  }) => boolean;
46
- bubbleMenuOptions: Record<string, any>;
46
+ tippyOptions: Record<string, any>;
47
47
  handleAdminColorChange: (color: {
48
48
  id: string;
49
49
  name: string;