@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
@@ -53,5 +53,10 @@ export declare const resolveGlobalPresetIntoStyle: (style: object | undefined, t
53
53
  * updates without re-resolving a preset.
54
54
  */
55
55
  export declare const applyDetachedStyleOverride: <T extends object>(current: T | undefined, updates: Partial<T>, textStyleOptions: TextStyleOptions | undefined) => T;
56
- export declare const applyStyleFields: (content: Content, args: SectionToolArguments, sectionType: string, textStyleOptions?: TextStyleOptions) => void;
56
+ /**
57
+ * Rewrites the stored RTE HTML's inline colour marks. Injectable for tests;
58
+ * the default uses the external Tiptap editor (font-propagation precedent).
59
+ */
60
+ export type ApplyColorToRTE = (html: string, color: string) => string;
61
+ export declare const applyStyleFields: (content: Content, args: SectionToolArguments, sectionType: string, textStyleOptions?: TextStyleOptions, applyColor?: ApplyColorToRTE) => void;
57
62
  export {};
@@ -1,5 +1,8 @@
1
1
  import { BUTTON_LINK_TYPE } from '../../brand-page/models';
2
2
  import { isTiptapDocument, } from '../parsers/section-tool-arguments';
3
+ import { hasRTEContent } from '../../brand-page-maker/utils';
4
+ import { useExternalRichTextEditor } from '../../brand-page-maker/composables/rich-text-editor/useRichTextEditor';
5
+ import { applyStyleToRTEText } from '../helpers/rte.helpers';
3
6
  import { getSectionFieldMap, getStyleFieldMap } from './section-field-maps';
4
7
  const isUrlField = (aiKey) => aiKey.endsWith('_url');
5
8
  export const isValidUrl = (value) => {
@@ -117,22 +120,55 @@ export const applyDetachedStyleOverride = (current, updates, textStyleOptions) =
117
120
  ...resolveGlobalPresetIntoStyle(current, textStyleOptions),
118
121
  ...updates,
119
122
  });
120
- export const applyStyleFields = (content, args, sectionType, textStyleOptions) => {
123
+ export const applyStyleFields = (content, args, sectionType, textStyleOptions, applyColor) => {
121
124
  const styleMap = getStyleFieldMap(sectionType);
122
125
  if (!styleMap)
123
126
  return;
124
127
  const record = content;
125
- for (const [aiKey, modelKey] of Object.entries(styleMap)) {
126
- if (!(aiKey in args) || !args[aiKey] || typeof args[aiKey] !== 'object')
127
- continue;
128
- const aiStyle = args[aiKey];
129
- const filtered = {};
130
- for (const [k, v] of Object.entries(aiStyle)) {
131
- const normalized = normalizeStyleValue(k, v);
132
- if (normalized !== undefined)
133
- filtered[k] = normalized;
128
+ let editor;
129
+ const applyColorToHtml = applyColor ??
130
+ ((html, color) => {
131
+ editor = editor ?? useExternalRichTextEditor().externalEditor;
132
+ return applyStyleToRTEText(editor, html, {
133
+ color,
134
+ });
135
+ });
136
+ try {
137
+ for (const [aiKey, modelKey] of Object.entries(styleMap)) {
138
+ if (!(aiKey in args) || !args[aiKey] || typeof args[aiKey] !== 'object')
139
+ continue;
140
+ const aiStyle = args[aiKey];
141
+ const filtered = {};
142
+ for (const [k, v] of Object.entries(aiStyle)) {
143
+ const normalized = normalizeStyleValue(k, v);
144
+ if (normalized !== undefined)
145
+ filtered[k] = normalized;
146
+ }
147
+ const resolved = resolveGlobalPresetIntoStyle(content[modelKey], textStyleOptions);
148
+ record[modelKey] = { ...resolved, ...filtered, textStyleType: undefined };
149
+ // A colour patch without new text leaves the field's EXISTING inline
150
+ // textStyle marks in place — and inline marks override every style layer
151
+ // at render, so the old colour survives on a recoloured band (invisible
152
+ // text, AI QA 2026-07-05 rerun). Propagate the new colour into the
153
+ // stored HTML, mirroring global-font-propagation for font families.
154
+ const textKey = modelKey.endsWith('Style')
155
+ ? modelKey.slice(0, -'Style'.length)
156
+ : undefined;
157
+ const textAiKey = aiKey.endsWith('_style')
158
+ ? aiKey.slice(0, -'_style'.length)
159
+ : undefined;
160
+ const newColor = filtered.color;
161
+ if (textKey &&
162
+ typeof newColor === 'string' &&
163
+ newColor &&
164
+ !(textAiKey && textAiKey in args) &&
165
+ typeof record[textKey] === 'string' &&
166
+ hasRTEContent(record[textKey])) {
167
+ record[textKey] = applyColorToHtml(record[textKey], newColor);
168
+ }
134
169
  }
135
- const resolved = resolveGlobalPresetIntoStyle(content[modelKey], textStyleOptions);
136
- record[modelKey] = { ...resolved, ...filtered, textStyleType: undefined };
170
+ }
171
+ finally {
172
+ editor?.destroy();
137
173
  }
138
174
  };
@@ -0,0 +1,2 @@
1
+ import { type ValidationContext } from '../../sanitizers/section-args-validator';
2
+ export declare function validateSupportMe(args: Record<string, unknown>, ctx: ValidationContext): string[];
@@ -0,0 +1,17 @@
1
+ import { MAX_TITLE_LENGTH, MAX_DESCRIPTION_LENGTH, } from '../../../brand-page/constants/font.constants';
2
+ import { DISPLAY_STYLE_PREVIEW, DISPLAY_STYLE_COLLAPSED, } from '../../../brand-page/constants';
3
+ import { enumCheck, runChecks, styleCheck, textCheck, } from '../../sanitizers/section-args-validator';
4
+ const CHECKS = [
5
+ textCheck('title', MAX_TITLE_LENGTH),
6
+ textCheck('description', MAX_DESCRIPTION_LENGTH),
7
+ textCheck('success_message', MAX_DESCRIPTION_LENGTH),
8
+ styleCheck('title_style'),
9
+ styleCheck('heading_style'),
10
+ styleCheck('description_style'),
11
+ styleCheck('item_text_style'),
12
+ styleCheck('button_text_style'),
13
+ enumCheck('display_style', [DISPLAY_STYLE_PREVIEW, DISPLAY_STYLE_COLLAPSED], 'support-me'),
14
+ ];
15
+ export function validateSupportMe(args, ctx) {
16
+ return runChecks(CHECKS, args, ctx);
17
+ }
@@ -0,0 +1,17 @@
1
+ import { type BrandPageModel } from '../../brand-page/models';
2
+ import type { Logger } from '../logger';
3
+ import { BaseMetadataBuilder, type BuilderResult, type MetadataBuilderRequest } from '../models';
4
+ export interface UpdateTextPayload {
5
+ contentId: string;
6
+ fieldName: string;
7
+ newText: string;
8
+ maxCharacters?: number;
9
+ }
10
+ export declare const buildUpdateTextRequest: (id: string, payload: UpdateTextPayload) => MetadataBuilderRequest<UpdateTextPayload>;
11
+ export declare class UpdateContentTextBuilder extends BaseMetadataBuilder<UpdateTextPayload> {
12
+ constructor(request: MetadataBuilderRequest<UpdateTextPayload>, logger?: Logger);
13
+ validateAsync(): Promise<{
14
+ errors: string[];
15
+ }>;
16
+ buildAsync(model: BrandPageModel): Promise<BuilderResult>;
17
+ }
@@ -0,0 +1,103 @@
1
+ import {} from '../../brand-page/models';
2
+ import { BaseMetadataBuilder, BUILDER_TYPES, } from '../models';
3
+ import { hasRTEContent, replaceTextInRTE } from '../../brand-page-maker/utils';
4
+ export const buildUpdateTextRequest = (id, payload) => {
5
+ return {
6
+ id,
7
+ type: BUILDER_TYPES.UPDATE_CONTENT_TEXT,
8
+ payload,
9
+ };
10
+ };
11
+ const updateTextField = (target, fieldName, newText) => {
12
+ // Check if this is an array item path like "textItems.0.text"
13
+ const match = fieldName.match(/^(\w+)\.(\d+)\.(\w+)$/);
14
+ if (match) {
15
+ const [, arrayName, index, property] = match;
16
+ const array = target[arrayName];
17
+ if (Array.isArray(array) && array[+index]) {
18
+ const existingText = array[+index][property];
19
+ const updatedValue = existingText &&
20
+ typeof existingText === 'string' &&
21
+ hasRTEContent(existingText)
22
+ ? replaceTextInRTE(existingText, newText)
23
+ : newText;
24
+ // Create a new array with the updated item to trigger reactivity
25
+ const newArray = [...array];
26
+ newArray[+index] = {
27
+ ...newArray[+index],
28
+ [property]: updatedValue,
29
+ };
30
+ target[arrayName] = newArray;
31
+ }
32
+ }
33
+ else {
34
+ // Simple field
35
+ const existingText = target[fieldName];
36
+ if (existingText &&
37
+ typeof existingText === 'string' &&
38
+ hasRTEContent(existingText)) {
39
+ target[fieldName] = replaceTextInRTE(existingText, newText);
40
+ }
41
+ else {
42
+ target[fieldName] = newText;
43
+ }
44
+ }
45
+ };
46
+ export class UpdateContentTextBuilder extends BaseMetadataBuilder {
47
+ constructor(request, logger) {
48
+ super(request, logger);
49
+ }
50
+ validateAsync() {
51
+ const newText = this.request.payload?.newText ?? '';
52
+ const errors = [];
53
+ const maxChars = this.request.payload?.maxCharacters ?? 2000;
54
+ if (newText.length > maxChars) {
55
+ errors.push(`Text exceeds maximum allowed length of ${maxChars}`);
56
+ }
57
+ this.log({
58
+ message: `Validation called`,
59
+ errors,
60
+ });
61
+ return Promise.resolve({ errors: errors });
62
+ }
63
+ async buildAsync(model) {
64
+ this.log(`Build called`);
65
+ const { contentId, fieldName, newText } = this.request.payload;
66
+ const validation = await this.validateAsync();
67
+ if (validation.errors.length) {
68
+ return {
69
+ request: this.request,
70
+ model,
71
+ errors: validation.errors,
72
+ };
73
+ }
74
+ let updated = false;
75
+ for (const page of model.pages) {
76
+ for (const content of page.contents) {
77
+ // Use includes to handle potential ID format differences
78
+ if (content.id.includes(contentId) || contentId.includes(content.id)) {
79
+ this.log({
80
+ message: `Content found`,
81
+ model,
82
+ });
83
+ updateTextField(content, fieldName, newText);
84
+ this.log({
85
+ message: `Successfully updated text content.`,
86
+ model,
87
+ });
88
+ updated = true;
89
+ break;
90
+ }
91
+ }
92
+ }
93
+ return {
94
+ request: this.request,
95
+ model,
96
+ errors: updated
97
+ ? undefined
98
+ : [
99
+ `Could not update the text because content with ID "${contentId}" not found.`,
100
+ ],
101
+ };
102
+ }
103
+ }
@@ -0,0 +1,16 @@
1
+ import { type BrandPageModel, type TextStyleDeclaration } from '../../brand-page/models';
2
+ import { BaseMetadataBuilder, type BuilderResult, type MetadataBuilderRequest } from '../models';
3
+ import type { Logger } from '../logger';
4
+ export interface UpdateTextStylePayload {
5
+ contentId: string;
6
+ fieldName: string;
7
+ newStyles: TextStyleDeclaration;
8
+ }
9
+ export declare const buildUpdateTextStyleRequest: (id: string, payload: UpdateTextStylePayload) => MetadataBuilderRequest<UpdateTextStylePayload>;
10
+ export declare class UpdateContentTextStyleBuilder extends BaseMetadataBuilder<UpdateTextStylePayload> {
11
+ constructor(request: MetadataBuilderRequest<UpdateTextStylePayload>, logger?: Logger);
12
+ validateAsync(): Promise<{
13
+ errors: string[];
14
+ }>;
15
+ buildAsync(model: BrandPageModel): Promise<BuilderResult>;
16
+ }
@@ -0,0 +1,216 @@
1
+ import {} from '../../brand-page/models';
2
+ import { BaseMetadataBuilder, BUILDER_TYPES, } from '../models';
3
+ import { hasRTEContent } from '../../brand-page-maker/utils';
4
+ import { useExternalRichTextEditor } from '../../brand-page-maker/composables/rich-text-editor/useRichTextEditor';
5
+ import { applyStyleToRTEText } from '../helpers/rte.helpers';
6
+ import { letterSpacingValueConvertor } from '../../brand-page-maker/convertors/letter-spacing-value.convertor';
7
+ export const buildUpdateTextStyleRequest = (id, payload) => {
8
+ return {
9
+ id,
10
+ type: BUILDER_TYPES.UPDATE_CONTENT_TEXT_STYLE,
11
+ payload,
12
+ };
13
+ };
14
+ const mergeStyles = (currentStyle, stylesToUpdate, textStyleOptions) => {
15
+ let merged = { ...currentStyle };
16
+ // If content uses a textStyleType preset (e.g. "titles"), resolve the preset
17
+ // styles into the style object before clearing the preset reference.
18
+ // This ensures properties like fontSize, fontFamily etc. are preserved
19
+ // when the AI only changes a single property like color.
20
+ if (merged.textStyleType && textStyleOptions?.[merged.textStyleType]) {
21
+ const presetStyle = textStyleOptions[merged.textStyleType].style;
22
+ merged = { ...merged, ...presetStyle };
23
+ merged.textStyleType = undefined;
24
+ }
25
+ Object.entries(stylesToUpdate).forEach(([key, value]) => {
26
+ if (value === null) {
27
+ // backgroundColor: null means "remove background color"
28
+ if (key === 'backgroundColor') {
29
+ merged.backgroundColor = '';
30
+ }
31
+ // All other null values mean "not changed" — skip to preserve existing values
32
+ return;
33
+ }
34
+ merged[key] = value;
35
+ });
36
+ return merged;
37
+ };
38
+ const updateRTEText = (text, style) => {
39
+ if (!text || typeof text !== 'string' || !hasRTEContent(text)) {
40
+ return text;
41
+ }
42
+ const { externalEditor } = useExternalRichTextEditor();
43
+ const updatedText = applyStyleToRTEText(externalEditor, text, style);
44
+ externalEditor.destroy();
45
+ return updatedText;
46
+ };
47
+ const findStyleKey = (target, property) => {
48
+ // Try exact match first (e.g., 'testimonialsStyle')
49
+ const exactKey = `${property}Style`;
50
+ if (exactKey in target)
51
+ return exactKey;
52
+ // Try singular form (e.g., 'testimonialStyle' for 'testimonials')
53
+ if (property.endsWith('s')) {
54
+ const singularKey = `${property.slice(0, -1)}Style`;
55
+ if (singularKey in target)
56
+ return singularKey;
57
+ }
58
+ // Try plural form (edge case)
59
+ const pluralKey = `${property}sStyle`;
60
+ if (pluralKey in target)
61
+ return pluralKey;
62
+ return exactKey; // fallback to exact match
63
+ };
64
+ const updateSharedArrayStyle = (content, property, stylesToUpdate, textStyleOptions) => {
65
+ const styleKey = findStyleKey(content, property);
66
+ if (!styleKey)
67
+ return;
68
+ const currentStyle = content[styleKey] || {};
69
+ const mergedStyle = mergeStyles(currentStyle, stylesToUpdate, textStyleOptions);
70
+ content[styleKey] = mergedStyle;
71
+ };
72
+ const updateArrayItemStyle = (content, fieldName, index, property, stylesToUpdate, textStyleOptions) => {
73
+ const currentContentItems = content[fieldName];
74
+ if (!Array.isArray(currentContentItems) || !currentContentItems[+index])
75
+ return;
76
+ const contentItem = currentContentItems[+index];
77
+ const styleKey = `${property}Style`;
78
+ const currentStyle = contentItem[styleKey] || {};
79
+ const mergedStyle = mergeStyles(currentStyle, stylesToUpdate, textStyleOptions);
80
+ const newContentItems = [...currentContentItems];
81
+ newContentItems[+index] = {
82
+ ...newContentItems[+index],
83
+ [styleKey]: mergedStyle,
84
+ [property]: updateRTEText(contentItem[property], mergedStyle),
85
+ };
86
+ content[fieldName] = newContentItems;
87
+ };
88
+ const updateTextStyle = (content, fieldName, stylesToUpdate, textStyleOptions) => {
89
+ // Check if fieldName is in the format of "fieldName.index.fieldItem"
90
+ const matchFieldItems = fieldName.match(/^(\w+)\.(\d+)\.(.+)$/);
91
+ if (matchFieldItems) {
92
+ const [, fieldName, index, fieldItem] = matchFieldItems;
93
+ const array = content[fieldName];
94
+ if (!Array.isArray(array) || !array[+index])
95
+ return;
96
+ const item = array[+index];
97
+ const itemStyleKey = `${fieldItem}Style`;
98
+ const hasItemStyle = itemStyleKey in item;
99
+ if (hasItemStyle) {
100
+ updateArrayItemStyle(content, fieldName, +index, fieldItem, stylesToUpdate, textStyleOptions);
101
+ }
102
+ else {
103
+ updateSharedArrayStyle(content, fieldItem, stylesToUpdate, textStyleOptions);
104
+ }
105
+ }
106
+ else {
107
+ const styleKey = `${fieldName}Style`;
108
+ const currentStyle = content[styleKey] || {};
109
+ const mergedStyle = mergeStyles(currentStyle, stylesToUpdate, textStyleOptions);
110
+ content[styleKey] = mergedStyle;
111
+ content[fieldName] = updateRTEText(content[fieldName], mergedStyle);
112
+ }
113
+ };
114
+ export class UpdateContentTextStyleBuilder extends BaseMetadataBuilder {
115
+ constructor(request, logger) {
116
+ super(request, logger);
117
+ }
118
+ validateAsync() {
119
+ const { newStyles } = this.request.payload;
120
+ const errors = [];
121
+ // Validate lineHeight: must be between 0 and 2.5 inclusive, snap to 0.1 step
122
+ if (newStyles.lineHeight !== undefined && newStyles.lineHeight !== null) {
123
+ const lineHeightValue = parseFloat(String(newStyles.lineHeight));
124
+ if (isNaN(lineHeightValue) ||
125
+ lineHeightValue < 0 ||
126
+ lineHeightValue > 2.5) {
127
+ errors.push('Line height must be a value between 0 and 2.5 inclusive.');
128
+ }
129
+ else {
130
+ // Snap to 0.1 increments to match the UI slider step
131
+ newStyles.lineHeight = String(Math.floor(lineHeightValue * 10) / 10);
132
+ }
133
+ }
134
+ // Validate and normalize letterSpacing: AI sends unitless 0-100, convert to em
135
+ if (newStyles.letterSpacing !== undefined &&
136
+ newStyles.letterSpacing !== null) {
137
+ const letterSpacingStr = String(newStyles.letterSpacing);
138
+ if (/[a-zA-Z]/.test(letterSpacingStr)) {
139
+ errors.push('Letter spacing must be a unitless value between 0 and 100.');
140
+ }
141
+ else {
142
+ const letterSpacingValue = parseFloat(letterSpacingStr);
143
+ if (isNaN(letterSpacingValue) ||
144
+ letterSpacingValue < 0 ||
145
+ letterSpacingValue > 100) {
146
+ errors.push('Letter spacing must be between 0 and 100 inclusive.');
147
+ }
148
+ else {
149
+ newStyles.letterSpacing = letterSpacingValueConvertor.convertBack(String(letterSpacingValue)).letterSpacing;
150
+ }
151
+ }
152
+ }
153
+ // Validate fontSize: must be in 'em' unit and between 0.75em and 8em inclusive
154
+ if (newStyles?.fontSize != null) {
155
+ const fontSizeStr = String(newStyles.fontSize);
156
+ const fontSizeMatch = fontSizeStr.match(/^(-?\d*\.?\d+)em$/);
157
+ if (!fontSizeMatch) {
158
+ errors.push('Font size must be in "em" unit (e.g., "1.5em").');
159
+ }
160
+ else {
161
+ const fontSizeValue = parseFloat(fontSizeMatch[1]);
162
+ if (isNaN(fontSizeValue) || fontSizeValue < 0.75 || fontSizeValue > 8) {
163
+ errors.push('Font size must be between 0.75em and 8em inclusive. If unitless from user always treat as px and convert to em using 16px = 1em ratio.');
164
+ }
165
+ }
166
+ }
167
+ return Promise.resolve({ errors });
168
+ }
169
+ async buildAsync(model) {
170
+ this.log(`Build called`);
171
+ const validation = await this.validateAsync();
172
+ if (validation.errors.length) {
173
+ return {
174
+ request: this.request,
175
+ model,
176
+ errors: validation.errors,
177
+ };
178
+ }
179
+ const { contentId, fieldName, newStyles } = this.request.payload;
180
+ // Filter out undefined values
181
+ const stylesToUpdate = Object.entries(newStyles).reduce((acc, [key, value]) => {
182
+ if (value !== undefined) {
183
+ acc[key] = value;
184
+ }
185
+ return acc;
186
+ }, {});
187
+ let updated = false;
188
+ for (const page of model.pages) {
189
+ for (const content of page.contents) {
190
+ // Use includes to handle potential ID format differences
191
+ if (content.id.includes(contentId) || contentId.includes(content.id)) {
192
+ this.log({
193
+ message: `Content found`,
194
+ model,
195
+ });
196
+ updateTextStyle(content, fieldName, stylesToUpdate, model.styles?.textStyles?.textStyleOptions);
197
+ this.log({
198
+ message: `Successfully updated text style content.`,
199
+ model,
200
+ });
201
+ updated = true;
202
+ break;
203
+ }
204
+ }
205
+ }
206
+ return {
207
+ request: this.request,
208
+ model,
209
+ errors: updated
210
+ ? undefined
211
+ : [
212
+ `Could not update the text style because content with ID "${contentId}" not found.`,
213
+ ],
214
+ };
215
+ }
216
+ }
@@ -1,18 +1,20 @@
1
+ import type { TextStyleDeclaration } from '../../brand-page';
2
+ import type { Editor } from '@tiptap/vue-3';
3
+ export declare const applyStyleToRTEText: (externalEditor: Editor, contentText: string, newContentStyle: TextStyleDeclaration) => string;
1
4
  /**
2
5
  * Converts a Tiptap JSON document (ProseMirror document model) to an HTML
3
- * string via Tiptap's schema-driven static renderer (renderRteToHtml →
4
- * renderToHTMLString). DOM-less and editor-free, so it runs on the server
5
- * (Nitro/Node), not just the browser — unlike the previous headless-Editor
6
- * implementation (BP-5787: the AI section builders no longer need a `document`).
6
+ * string using a headless Tiptap Editor instance.
7
7
  *
8
8
  * Returns the value unchanged if it is already a string.
9
- * Returns an empty string for null/undefined or any non-Tiptap-document value.
9
+ * Returns an empty string for null/undefined.
10
10
  *
11
- * Note: to prevent saved copy being wiped (BP-5669), structural validity of any
12
- * AI-emitted Tiptap doc is checked upstream by `rteSchemaCheck` in
13
- * `section-args-validator.ts` against the editor's real ProseMirror schema. The
14
- * validator surfaces a clear error into `BuilderResult.errors`, which the
15
- * AI-chat retry loop reads via `tool_result.errorMessage` and uses to re-emit a
16
- * corrected payload.
11
+ * Note: Tiptap's `setContent` does NOT throw on malformed input — it
12
+ * silently drops content and returns `<p></p>`. To prevent saved copy
13
+ * being wiped (BP-5669), structural validity of any AI-emitted Tiptap
14
+ * doc is checked upstream by `rteSchemaCheck` in
15
+ * `section-args-validator.ts` using the editor's real ProseMirror
16
+ * schema. The validator surfaces a clear error into
17
+ * `BuilderResult.errors`, which the AI-chat retry loop reads via
18
+ * `tool_result.errorMessage` and uses to re-emit a corrected payload.
17
19
  */
18
20
  export declare const tiptapJsonToHtml: (value: unknown) => string;
@@ -1,26 +1,85 @@
1
- import { renderRteToHtml } from '../../brand-page-maker/utils';
2
- import { isTiptapDocument } from '../parsers/section-tool-arguments';
1
+ import { getRTEColor } from '../../brand-page-maker/utils';
2
+ import { useExternalRichTextEditor } from '../../brand-page-maker/composables/rich-text-editor/useRichTextEditor';
3
+ import { getRenderText } from '../../brand-page/utils';
4
+ import { ESCAPED_NEWLINE_CHARACTER } from '../../constants/ui';
5
+ import { isTiptapDocument, } from '../parsers/section-tool-arguments';
6
+ export const applyStyleToRTEText = (externalEditor, contentText, newContentStyle) => {
7
+ if (!contentText) {
8
+ return contentText;
9
+ }
10
+ const content = contentText.includes(ESCAPED_NEWLINE_CHARACTER)
11
+ ? getRenderText(contentText)
12
+ : contentText;
13
+ externalEditor.commands.setContent(content);
14
+ let chain = externalEditor.chain().selectAll();
15
+ if (newContentStyle?.fontFamily) {
16
+ chain = chain.setFontFamily(newContentStyle.fontFamily);
17
+ }
18
+ if (newContentStyle?.fontSize) {
19
+ chain = chain.setFontSize(newContentStyle.fontSize);
20
+ }
21
+ if (newContentStyle?.letterSpacing) {
22
+ chain = chain.setLetterSpacing(newContentStyle.letterSpacing);
23
+ }
24
+ if (newContentStyle?.lineHeight) {
25
+ chain = chain.setLineHeight(newContentStyle.lineHeight);
26
+ }
27
+ if (newContentStyle?.color) {
28
+ chain = chain.setMark('textStyle', {
29
+ color: getRTEColor(newContentStyle.color, 'text'),
30
+ });
31
+ }
32
+ // Handle backgroundColor
33
+ if ('backgroundColor' in (newContentStyle || {})) {
34
+ chain = newContentStyle.backgroundColor
35
+ ? chain.setMark('highlight', {
36
+ color: getRTEColor(newContentStyle.backgroundColor, 'background'),
37
+ })
38
+ : chain.unsetHighlight();
39
+ }
40
+ if (newContentStyle?.textAlign) {
41
+ chain = chain.setTextAlign(newContentStyle.textAlign);
42
+ }
43
+ const hasStrike = newContentStyle?.textDecoration?.includes('line-through');
44
+ const hasUnderline = newContentStyle?.textDecoration?.includes('underline');
45
+ chain = hasStrike ? chain.setStrike() : chain.unsetStrike();
46
+ chain = hasUnderline ? chain.setUnderline() : chain.unsetUnderline();
47
+ chain =
48
+ newContentStyle?.fontWeight === 'bold'
49
+ ? chain.setBold()
50
+ : chain.unsetBold();
51
+ chain =
52
+ newContentStyle?.fontStyle === 'italic'
53
+ ? chain.setItalic()
54
+ : chain.unsetItalic();
55
+ chain.run();
56
+ const html = externalEditor.getHTML();
57
+ return html;
58
+ };
3
59
  /**
4
60
  * Converts a Tiptap JSON document (ProseMirror document model) to an HTML
5
- * string via Tiptap's schema-driven static renderer (renderRteToHtml →
6
- * renderToHTMLString). DOM-less and editor-free, so it runs on the server
7
- * (Nitro/Node), not just the browser — unlike the previous headless-Editor
8
- * implementation (BP-5787: the AI section builders no longer need a `document`).
61
+ * string using a headless Tiptap Editor instance.
9
62
  *
10
63
  * Returns the value unchanged if it is already a string.
11
- * Returns an empty string for null/undefined or any non-Tiptap-document value.
64
+ * Returns an empty string for null/undefined.
12
65
  *
13
- * Note: to prevent saved copy being wiped (BP-5669), structural validity of any
14
- * AI-emitted Tiptap doc is checked upstream by `rteSchemaCheck` in
15
- * `section-args-validator.ts` against the editor's real ProseMirror schema. The
16
- * validator surfaces a clear error into `BuilderResult.errors`, which the
17
- * AI-chat retry loop reads via `tool_result.errorMessage` and uses to re-emit a
18
- * corrected payload.
66
+ * Note: Tiptap's `setContent` does NOT throw on malformed input — it
67
+ * silently drops content and returns `<p></p>`. To prevent saved copy
68
+ * being wiped (BP-5669), structural validity of any AI-emitted Tiptap
69
+ * doc is checked upstream by `rteSchemaCheck` in
70
+ * `section-args-validator.ts` using the editor's real ProseMirror
71
+ * schema. The validator surfaces a clear error into
72
+ * `BuilderResult.errors`, which the AI-chat retry loop reads via
73
+ * `tool_result.errorMessage` and uses to re-emit a corrected payload.
19
74
  */
20
75
  export const tiptapJsonToHtml = (value) => {
21
76
  if (typeof value === 'string')
22
77
  return value;
23
78
  if (!isTiptapDocument(value))
24
79
  return '';
25
- return renderRteToHtml(value);
80
+ const { externalEditor } = useExternalRichTextEditor();
81
+ externalEditor.commands.setContent(value);
82
+ const html = externalEditor.getHTML();
83
+ externalEditor.destroy();
84
+ return html;
26
85
  };
@@ -1,7 +1,9 @@
1
1
  import cloneDeep from 'lodash.clonedeep';
2
2
  import {} from '../brand-page/models';
3
3
  import { BUILDER_TYPES, } from './models';
4
- import { BannerSectionBuilder, BookingSectionBuilder, AboutSectionBuilder, ContactFormBuilder, DividerSectionBuilder, TextSectionBuilder, TestimonialSectionBuilder, ImagesSectionBuilder, ShapesSectionBuilder, SocialLinksBuilder, ImageGalleryBuilder, ProfileSectionBuilder, MailingListSectionBuilder, ButtonSectionBuilder, DeleteSectionBuilder, MoveSectionBuilder, } from './builders/section-builders';
4
+ import { UpdateContentTextBuilder } from './builders/update-content-text-builder';
5
+ import { UpdateContentTextStyleBuilder } from './builders/update-content-text-style-builder';
6
+ import { BannerSectionBuilder, BookingSectionBuilder, SupportMeBuilder, AboutSectionBuilder, ContactFormBuilder, DividerSectionBuilder, TextSectionBuilder, TestimonialSectionBuilder, ImagesSectionBuilder, ShapesSectionBuilder, SocialLinksBuilder, ImageGalleryBuilder, ProfileSectionBuilder, MailingListSectionBuilder, ButtonSectionBuilder, DeleteSectionBuilder, MoveSectionBuilder, } from './builders/section-builders';
5
7
  import { AddPageBuilder } from './builders/add-page-builder';
6
8
  import { RemovePageBuilder } from './builders/remove-page-builder';
7
9
  import { RenamePageBuilder } from './builders/rename-page-builder';
@@ -13,9 +15,12 @@ import { HeaderBuilder } from './builders/header-builder';
13
15
  import { UndoBuilder } from './builders/undo-builder';
14
16
  // Lazy initialization to avoid circular dependency issues
15
17
  const getBuilderRegistry = () => ({
18
+ [BUILDER_TYPES.UPDATE_CONTENT_TEXT]: UpdateContentTextBuilder,
19
+ [BUILDER_TYPES.UPDATE_CONTENT_TEXT_STYLE]: UpdateContentTextStyleBuilder,
16
20
  // Section builders (create)
17
21
  [BUILDER_TYPES.CREATE_BANNER_SECTION]: BannerSectionBuilder,
18
22
  [BUILDER_TYPES.CREATE_BOOKING_SECTION]: BookingSectionBuilder,
23
+ [BUILDER_TYPES.CREATE_SUPPORT_ME]: SupportMeBuilder,
19
24
  [BUILDER_TYPES.CREATE_ABOUT_SECTION]: AboutSectionBuilder,
20
25
  [BUILDER_TYPES.CREATE_CONTACT_FORM]: ContactFormBuilder,
21
26
  [BUILDER_TYPES.CREATE_DIVIDER_SECTION]: DividerSectionBuilder,
@@ -42,6 +47,7 @@ const getBuilderRegistry = () => ({
42
47
  // Section builders (update)
43
48
  [BUILDER_TYPES.UPDATE_BANNER_SECTION]: BannerSectionBuilder,
44
49
  [BUILDER_TYPES.UPDATE_BOOKING_SECTION]: BookingSectionBuilder,
50
+ [BUILDER_TYPES.UPDATE_SUPPORT_ME]: SupportMeBuilder,
45
51
  [BUILDER_TYPES.UPDATE_ABOUT_SECTION]: AboutSectionBuilder,
46
52
  [BUILDER_TYPES.UPDATE_CONTACT_FORM]: ContactFormBuilder,
47
53
  [BUILDER_TYPES.UPDATE_DIVIDER_SECTION]: DividerSectionBuilder,
@@ -2,6 +2,8 @@ import { type BrandPageModel } from '../brand-page/models';
2
2
  import type { EventTracker } from '../brand-page-maker/composables/useEventTracker';
3
3
  import type { Logger } from './logger';
4
4
  export declare const BUILDER_TYPES: {
5
+ readonly UPDATE_CONTENT_TEXT: "update-content-text";
6
+ readonly UPDATE_CONTENT_TEXT_STYLE: "update-content-text-style";
5
7
  readonly CREATE_BANNER_SECTION: "create-banner-section";
6
8
  readonly CREATE_ABOUT_SECTION: "create-about-section";
7
9
  readonly CREATE_CONTACT_FORM: "create-contact-form";
@@ -27,6 +29,7 @@ export declare const BUILDER_TYPES: {
27
29
  readonly CREATE_TWITCH: "create-twitch";
28
30
  readonly CREATE_TIKTOK: "create-tiktok";
29
31
  readonly CREATE_BOOKING_SECTION: "create-booking-section";
32
+ readonly CREATE_SUPPORT_ME: "create-support-me";
30
33
  readonly UPDATE_BANNER_SECTION: "update-banner-section";
31
34
  readonly UPDATE_ABOUT_SECTION: "update-about-section";
32
35
  readonly UPDATE_CONTACT_FORM: "update-contact-form";
@@ -52,6 +55,7 @@ export declare const BUILDER_TYPES: {
52
55
  readonly UPDATE_TWITCH: "update-twitch";
53
56
  readonly UPDATE_TIKTOK: "update-tiktok";
54
57
  readonly UPDATE_BOOKING_SECTION: "update-booking-section";
58
+ readonly UPDATE_SUPPORT_ME: "update-support-me";
55
59
  readonly DELETE_SECTION: "delete-section";
56
60
  readonly MOVE_SECTION: "move-section";
57
61
  readonly ADD_PAGE: "add-page";