@designcrowd/library.brand-page 5.18.4 → 5.18.5

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 (162) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-DQLtpdLe.js → CreatedOnBrandCrowd-de-de-ciKpCAd9.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-CvEhlADd.js → CreatedOnBrandCrowd-en-us-CZbTS1AZ.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-pYQeTTC0.js → CreatedOnBrandCrowd-es-es-C8MExng5.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-CcE-iCEq.js → CreatedOnBrandCrowd-fr-ca-CO0L9NK2.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-CcE-iCEq.js → CreatedOnBrandCrowd-fr-fr-CO0L9NK2.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-OyhWWWyO.js → CreatedOnBrandCrowd-pt-br-zVDvBF2H.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-OyhWWWyO.js → CreatedOnBrandCrowd-pt-pt-zVDvBF2H.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-DH98FFLS.js → CreatedOnDcom-de-de-WrUSQdjf.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-DK67NN1r.js → CreatedOnDcom-en-us-BqC9YtkL.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-9-QU4BU6.js → CreatedOnDcom-es-es-BzH32Oya.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-U9J9H9VB.js → CreatedOnDcom-fr-ca-D7TYfCW0.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-DqdzB1DJ.js → CreatedOnDcom-fr-fr-DVlyfBtb.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-c4UiWtkB.js → CreatedOnDcom-pt-br-CSRB91ey.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-Do2qJsYp.js → CreatedOnDcom-pt-pt-9KMj5gpc.js} +1 -1
  15. package/lib/src/brand-page/models/navigation-styles.model.d.ts +7 -0
  16. package/lib/src/brand-page/models/navigation-styles.model.js +25 -2
  17. package/lib/src/brand-page/utils/migration/migration-16.d.ts +2 -0
  18. package/lib/src/brand-page/utils/migration/migration-16.js +47 -0
  19. package/lib/src/brand-page/utils/migration.util.js +7 -0
  20. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +7 -2
  21. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +7 -2
  22. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +8 -0
  23. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +7 -2
  24. package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.js +1 -0
  25. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +87 -2
  26. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.js +5 -0
  27. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +7 -2
  28. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +3 -0
  29. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.js +11 -0
  30. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +7 -2
  31. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +7 -2
  32. package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +7 -2
  33. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +7 -2
  34. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +9 -0
  35. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +20 -1
  36. package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +20 -0
  37. package/lib/src/brand-page-maker/composables/useEventTracker.js +17 -0
  38. package/lib/src/brand-page-maker/composables/useUndoRedoFlag.d.ts +17 -0
  39. package/lib/src/brand-page-maker/composables/useUndoRedoFlag.js +25 -0
  40. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +41 -2
  41. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +308 -14
  42. package/lib/src/brand-page-maker/stores/history/history-store.d.ts +83 -0
  43. package/lib/src/brand-page-maker/stores/history/history-store.js +495 -0
  44. package/lib/src/brand-page-maker/stores/logo-store/logo-store.d.ts +1 -0
  45. package/lib/src/brand-page-maker/stores/user/user-store.js +1 -0
  46. package/lib/src/bundled-translations-D1q3rSEz.js +175 -0
  47. package/lib/src/bundled-translations.de-DE-BxqLLwbh.js +175 -0
  48. package/lib/src/bundled-translations.es-ES-uh249NlJ.js +175 -0
  49. package/lib/src/bundled-translations.fr-CA-BEQmv2fX.js +175 -0
  50. package/lib/src/bundled-translations.fr-FR-BnNuCojH.js +175 -0
  51. package/lib/src/bundled-translations.pt-BR-CJUOxVlq.js +175 -0
  52. package/lib/src/bundled-translations.pt-PT-Ds9cMEqK.js +175 -0
  53. package/lib/src/bundles/bundled-translations.de-DE.json +3 -1
  54. package/lib/src/bundles/bundled-translations.es-ES.json +3 -1
  55. package/lib/src/bundles/bundled-translations.fr-CA.json +3 -1
  56. package/lib/src/bundles/bundled-translations.fr-FR.json +3 -1
  57. package/lib/src/bundles/bundled-translations.json +3 -1
  58. package/lib/src/bundles/bundled-translations.pt-BR.json +3 -1
  59. package/lib/src/bundles/bundled-translations.pt-PT.json +3 -1
  60. package/lib/src/constants/ui.d.ts +1 -0
  61. package/lib/src/css/library.brand-page-brandCrowd.min.css +77 -82
  62. package/lib/src/css/library.brand-page-brandPage.min.css +77 -83
  63. package/lib/src/css/library.brand-page-designCom.min.css +77 -82
  64. package/lib/src/css/library.brand-page-preview.min.css +77 -82
  65. package/lib/src/index.mjs +62 -60
  66. package/lib/src/{lib-BI3J4Mbk.js → lib-BXbo_N88.js} +35072 -34447
  67. package/lib/src/metadata-builder/builders/reorder-pages-builder.d.ts +13 -0
  68. package/lib/src/metadata-builder/builders/reorder-pages-builder.js +49 -0
  69. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +87 -2
  70. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +5 -0
  71. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.stories.js +1 -0
  72. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +23 -2
  73. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +16 -0
  74. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +7 -2
  75. package/lib/src/shared/content-settings/components/draggable-item-list/DraggableItemList.mixin.d.ts +3 -0
  76. package/lib/src/shared/content-settings/components/draggable-item-list/DraggableItemList.mixin.js +19 -2
  77. package/lib/src/shared/content-settings/components/form-fields-field/FormFieldsField.mixin.js +18 -8
  78. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +64 -0
  79. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.js +6 -0
  80. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +19 -0
  81. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.js +11 -0
  82. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +10 -2
  83. package/lib/src/shared/logo-settings/store/editable-logo-store.d.ts +5 -1
  84. package/lib/src/shared/logo-settings/store/editable-logo-store.js +31 -0
  85. package/lib/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.js +10 -8
  86. package/lib/src/shared/navigation-style-settings/store/index.js +1 -12
  87. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +24 -2
  88. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +10 -2
  89. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +23 -2
  90. package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +16 -0
  91. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +23 -2
  92. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +16 -0
  93. package/package.json +1 -1
  94. package/src/brand-page/components/button/Button.vue +2 -10
  95. package/src/brand-page/components/contact-form/ContactForm.vue +2 -2
  96. package/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.vue +4 -1
  97. package/src/brand-page/models/navigation-styles.model.ts +39 -1
  98. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -3
  99. package/src/brand-page/utils/migration/migration-16.test.ts +319 -0
  100. package/src/brand-page/utils/migration/migration-16.ts +75 -0
  101. package/src/brand-page/utils/migration.util.ts +8 -0
  102. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +9 -0
  103. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +2 -3
  104. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +1 -0
  105. package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.ts +5 -0
  106. package/src/brand-page-maker/components/color-palette/BpColorPalette.vue +9 -7
  107. package/src/brand-page-maker/components/cookie-collection/CookieSettings.vue +18 -17
  108. package/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.ts +13 -0
  109. package/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.vue +26 -3
  110. package/src/brand-page-maker/components/quick-link-bar/RedoButton.vue +66 -0
  111. package/src/brand-page-maker/components/quick-link-bar/UndoButton.vue +66 -0
  112. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.de-DE.json +6 -4
  113. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.es-ES.json +6 -4
  114. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.fr-CA.json +6 -4
  115. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.fr-FR.json +6 -4
  116. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.json +3 -1
  117. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.pt-BR.json +6 -4
  118. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.pt-PT.json +6 -4
  119. package/src/brand-page-maker/components/quick-link-bar/undo-redo-buttons.test.ts +116 -0
  120. package/src/brand-page-maker/components/save-contact/SaveContact.vue +12 -19
  121. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +10 -0
  122. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +24 -1
  123. package/src/brand-page-maker/composables/useEventTracker.ts +29 -0
  124. package/src/brand-page-maker/composables/useUndoRedoFlag.ts +30 -0
  125. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +377 -0
  126. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +371 -18
  127. package/src/brand-page-maker/stores/history/history-store.test.ts +1120 -0
  128. package/src/brand-page-maker/stores/history/history-store.ts +660 -0
  129. package/src/brand-page-maker/stores/logo-store/logo-store.ts +5 -0
  130. package/src/brand-page-maker/stores/user/user-store.ts +1 -0
  131. package/src/bundles/bundled-translations.de-DE.json +3 -1
  132. package/src/bundles/bundled-translations.es-ES.json +3 -1
  133. package/src/bundles/bundled-translations.fr-CA.json +3 -1
  134. package/src/bundles/bundled-translations.fr-FR.json +3 -1
  135. package/src/bundles/bundled-translations.json +3 -1
  136. package/src/bundles/bundled-translations.pt-BR.json +3 -1
  137. package/src/bundles/bundled-translations.pt-PT.json +3 -1
  138. package/src/constants/ui.ts +1 -0
  139. package/src/metadata-builder/builders/reorder-pages-builder.ts +80 -0
  140. package/src/shared/content-settings/components/color-field/ColorField.vue +10 -5
  141. package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +5 -0
  142. package/src/shared/content-settings/components/content-settings/ContentSettings.stories.ts +1 -0
  143. package/src/shared/content-settings/components/draggable-item-list/DraggableItemList.mixin.ts +19 -2
  144. package/src/shared/content-settings/components/draggable-item-list/DraggableItemList.vue +1 -1
  145. package/src/shared/content-settings/components/form-fields-field/FormFieldsField.mixin.ts +26 -10
  146. package/src/shared/content-settings/components/logo-selection-field/LogoSelection.vue +63 -48
  147. package/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.vue +4 -0
  148. package/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.ts +7 -0
  149. package/src/shared/content-settings/components/text-field/TextField.vue +1 -0
  150. package/src/shared/content-settings/components/text-image-field/TextImageField.vue +33 -4
  151. package/src/shared/logo-settings/components/EditLogoSettings.mixin.ts +11 -0
  152. package/src/shared/logo-settings/store/editable-logo-store.ts +42 -1
  153. package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.ts +17 -11
  154. package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.vue +4 -1
  155. package/src/shared/navigation-style-settings/store/index.ts +1 -21
  156. package/lib/src/bundled-translations-B5Fkt3qd.js +0 -175
  157. package/lib/src/bundled-translations.de-DE-DpdVePM9.js +0 -175
  158. package/lib/src/bundled-translations.es-ES-BsIcrzZF.js +0 -175
  159. package/lib/src/bundled-translations.fr-CA-G1XCp2Qh.js +0 -175
  160. package/lib/src/bundled-translations.fr-FR-BdwLXOnB.js +0 -175
  161. package/lib/src/bundled-translations.pt-BR-Bvn5ePe7.js +0 -175
  162. package/lib/src/bundled-translations.pt-PT-CDtkb2k1.js +0 -175
@@ -112,16 +112,21 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
112
112
  hideChangeTemplateConfirmModal(): void;
113
113
  onBackgroundChanged(): void;
114
114
  onChangeTemplateConfirmModalCancel(): void;
115
- onChangeTemplateConfirmModalConfirm(): void;
115
+ onChangeTemplateConfirmModalConfirm(): Promise<void>;
116
116
  onContentChanged(): void;
117
117
  onStyleChanged(): void;
118
- onTemplateSelected(payload: import("@brand-page-maker/stores").OnTemplateSelectedPayload): void;
118
+ onTemplateSelected(payload: import("@brand-page-maker/stores").OnTemplateSelectedPayload): Promise<void>;
119
119
  setSelectedTabName(payload: any): void;
120
120
  showNextNotificationMessage(): Promise<void>;
121
121
  updateContent<TContent extends import("../../../brand-page").Content, P extends {
122
122
  id: string;
123
123
  content: TContent;
124
124
  }>(payload: P): Promise<void>;
125
+ _captureTemplateSwitchIfEnabled(): void;
126
+ applyHistorySnapshot(snapshot: import("../../../brand-page").BrandPageModel, activePageId?: string | undefined, logoEditsStr?: string | undefined): Promise<void>;
127
+ _syncLogoSettingsFromSnapshot(snapshot: import("../../../brand-page").BrandPageModel, logoEditsStr?: string | undefined): Promise<void>;
128
+ _navigateToActivePage(activePageId?: string | undefined): void;
129
+ _fallbackSidebarIfSelectedContentMissing(snapshot: import("../../../brand-page").BrandPageModel): void;
125
130
  export(): import("../../../brand-page").BrandPageModel;
126
131
  setBrandPageType({ brandPageType }: {
127
132
  brandPageType: "default" | "brandSite" | "brandContact";
@@ -432,16 +432,21 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
432
432
  hideChangeTemplateConfirmModal(): void;
433
433
  onBackgroundChanged(): void;
434
434
  onChangeTemplateConfirmModalCancel(): void;
435
- onChangeTemplateConfirmModalConfirm(): void;
435
+ onChangeTemplateConfirmModalConfirm(): Promise<void>;
436
436
  onContentChanged(): void;
437
437
  onStyleChanged(): void;
438
- onTemplateSelected(payload: import("@brand-page-maker/stores").OnTemplateSelectedPayload): void;
438
+ onTemplateSelected(payload: import("@brand-page-maker/stores").OnTemplateSelectedPayload): Promise<void>;
439
439
  setSelectedTabName(payload: any): void;
440
440
  showNextNotificationMessage(): Promise<void>;
441
441
  updateContent<TContent extends import("@brand-page").Content, P extends {
442
442
  id: string;
443
443
  content: TContent;
444
444
  }>(payload: P): Promise<void>;
445
+ _captureTemplateSwitchIfEnabled(): void;
446
+ applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string | undefined, logoEditsStr?: string | undefined): Promise<void>;
447
+ _syncLogoSettingsFromSnapshot(snapshot: import("@brand-page").BrandPageModel, logoEditsStr?: string | undefined): Promise<void>;
448
+ _navigateToActivePage(activePageId?: string | undefined): void;
449
+ _fallbackSidebarIfSelectedContentMissing(snapshot: import("@brand-page").BrandPageModel): void;
445
450
  export(): import("@brand-page").BrandPageModel;
446
451
  setBrandPageType({ brandPageType }: {
447
452
  brandPageType: "default" | "brandSite" | "brandContact";
@@ -10,6 +10,8 @@ import { usePageNavigationStore } from '../../../shared/page-navigation/store/pa
10
10
  import { navigateToPageByPageId } from '../../routing';
11
11
  import { useSnapshotStore, useAiWebsiteBuilderThreadStore, useAiCheckpointStore, useBrandPageContainerStore, useUiStore, } from '../../stores';
12
12
  import { useBrandPageMakerStore } from '../../stores';
13
+ import { useHistoryStore } from '../../stores/history/history-store';
14
+ import { useUndoRedoFlag } from '../useUndoRedoFlag';
13
15
  import { useBrandPageMakerUserStore } from '../../stores/user/user-store';
14
16
  import { useAiMetadataBuilder } from './useAiMetadataBuilder';
15
17
  import { pickErrorMessage, pickWsErrorMessage, buildSubmitErrorReport, } from './aiErrorCopy';
@@ -23,6 +25,8 @@ export function useAiWebsiteBuilderChat() {
23
25
  const aiThreadStore = useAiWebsiteBuilderThreadStore();
24
26
  const snapshotStore = useSnapshotStore();
25
27
  const brandPageMakerStore = useBrandPageMakerStore();
28
+ const historyStore = useHistoryStore();
29
+ const undoRedoEnabled = useUndoRedoFlag();
26
30
  const containerStore = useBrandPageContainerStore();
27
31
  const userStore = useBrandPageMakerUserStore();
28
32
  const uiStore = useUiStore();
@@ -298,6 +302,11 @@ export function useAiWebsiteBuilderChat() {
298
302
  navigateToPageByPageId(pageNavigationStore.activePageId);
299
303
  }
300
304
  await nextTick();
305
+ // One history entry per AI prompt (US-E1). `captureAiChangeset` cancels
306
+ // the auto-watcher's pending flush so the apply doesn't double-capture.
307
+ if (undoRedoEnabled.value) {
308
+ historyStore.captureAiChangeset();
309
+ }
301
310
  // Re-capture snapshot so subsequent messages reflect the updated page
302
311
  await snapshotStore.refreshSnapshotAsync();
303
312
  return {
@@ -21,6 +21,7 @@ import { buildInitialMarks, emToPx, isStyleChanged, pxToEm, sanitiseClientSideRT
21
21
  import { HYPERLINK_TYPE, } from '@brand-page';
22
22
  import { letterSpacingValueConvertor, colorConvertor, backgroundColorConvertor, } from '@brand-page-maker/convertors';
23
23
  import { useUiContentSettingsStore } from '@shared/content-settings/store';
24
+ import { useHistoryStore } from '@brand-page-maker/stores/history/history-store';
24
25
  import { AllSelection } from 'prosemirror-state';
25
26
  import { MaxLength } from './extensions/MaxLength';
26
27
  import { AutoLink } from './extensions/AutoLink';
@@ -72,6 +73,10 @@ export const useExternalRichTextEditor = () => {
72
73
  };
73
74
  };
74
75
  export const useRichTextEditor = (model, props, emit, fontSettings, fontStyleDropdownRef, selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyleTypeOptions, markedText, isHyperlinkPopupOpen, selectedLinkTypeValue) => {
76
+ const historyStore = useHistoryStore();
77
+ // TipTap rehydrates and writes back canonical HTML on mount — fold
78
+ // that into the current head instead of pushing a phantom entry.
79
+ historyStore.mergeNextMutation();
75
80
  const editor = new Editor({
76
81
  content: model.value ?? '',
77
82
  editable: !props.readOnly,
@@ -229,7 +234,14 @@ export const useRichTextEditor = (model, props, emit, fontSettings, fontStyleDro
229
234
  }
230
235
  });
231
236
  watch(() => model.value, (newValue) => {
232
- if (updateRichTextEditor.value && editor.getHTML() !== newValue) {
237
+ // Re-seed the editor when the model has been mutated from outside
238
+ // (history undo/redo, template switch, reorder). `!editor.isFocused`
239
+ // distinguishes "external mutation" from "user is typing in me" — the
240
+ // latter would wipe the user's cursor if we called setContent.
241
+ // `updateRichTextEditor.value` is retained as an explicit override for
242
+ // callers (reorder) that need to force a re-seed while focused.
243
+ const isExternalMutation = updateRichTextEditor.value || !editor.isFocused;
244
+ if (isExternalMutation && editor.getHTML() !== newValue) {
233
245
  editor.commands.setContent(newValue, false);
234
246
  updateRichTextEditor.value = false;
235
247
  //text style type is not switching when reordering
@@ -256,6 +268,13 @@ export const useRichTextEditor = (model, props, emit, fontSettings, fontStyleDro
256
268
  emit('update:modelValue', sanitizedData.sanitizedHtml);
257
269
  });
258
270
  editor.on('selectionUpdate', () => {
271
+ // Skip while a history snapshot is being applied — `setContent` fires
272
+ // selectionUpdate before the editor has fully rehydrated, which causes
273
+ // toolbar buttons (alignment, letter-spacing) to flash through bogus
274
+ // active states before settling. The editor emits a final selectionUpdate
275
+ // after apply completes, which lands the correct values (BP-5506).
276
+ if (historyStore.isApplyingSnapshot)
277
+ return;
259
278
  const textStyleAttributes = editor.getAttributes('textStyle');
260
279
  const highlightAttributes = editor.getAttributes('highlight');
261
280
  const focusedAlignment = editor.getAttributes(editor.state.selection.$anchor.node().type.name);
@@ -55,6 +55,10 @@ export declare const EVENTS: {
55
55
  WEBSITE_MAKER_DIGITAL_BUSINESS_CARDS_HIDE_POPUP: string;
56
56
  WEBSITE_MAKER_GETTY_VIDEO: string;
57
57
  WEBSITE_MAKER_SHIPPING_TOGGLE: string;
58
+ WEBSITE_MAKER_UNDO: string;
59
+ WEBSITE_MAKER_REDO: string;
60
+ WEBSITE_MAKER_HISTORY_CAPPED: string;
61
+ WEBSITE_MAKER_HISTORY_OVERSIZED: string;
58
62
  };
59
63
  export declare const SELECT_LOCATIONS: {
60
64
  MAKER_PREVIEW: string;
@@ -107,6 +111,22 @@ export declare const PUBLISH_OPTION_MODAL_CONTINUATION_EVENTS: {
107
111
  };
108
112
  declare const useEventTracker: () => {
109
113
  sendShippingToggleEvent: (isEnabled: boolean) => void;
114
+ sendUndoEvent: (props: {
115
+ entries_count: number;
116
+ actor: string | undefined;
117
+ }) => void;
118
+ sendRedoEvent: (props: {
119
+ entries_count: number;
120
+ actor: string | undefined;
121
+ }) => void;
122
+ sendHistoryCappedEvent: (props: {
123
+ entries_count: number;
124
+ size_bytes: number;
125
+ }) => void;
126
+ sendHistoryOversizedEvent: (props: {
127
+ attempted_bytes: number;
128
+ source: string;
129
+ }) => void;
110
130
  sendSaveContactEvent: () => void;
111
131
  sendStartForFreeEvent: () => void;
112
132
  sendFooterLinkClickEvent: (linkType: 'watermark_logo' | 'create_your_website') => void;
@@ -36,6 +36,10 @@ export const EVENTS = {
36
36
  WEBSITE_MAKER_DIGITAL_BUSINESS_CARDS_HIDE_POPUP: 'website_maker_digital_business_cards_hide_popup',
37
37
  WEBSITE_MAKER_GETTY_VIDEO: 'website_maker_getty_video',
38
38
  WEBSITE_MAKER_SHIPPING_TOGGLE: 'website_maker_shipping_toggle',
39
+ WEBSITE_MAKER_UNDO: 'website_maker_undo',
40
+ WEBSITE_MAKER_REDO: 'website_maker_redo',
41
+ WEBSITE_MAKER_HISTORY_CAPPED: 'website_maker_history_capped',
42
+ WEBSITE_MAKER_HISTORY_OVERSIZED: 'website_maker_history_oversized',
39
43
  };
40
44
  export const SELECT_LOCATIONS = {
41
45
  MAKER_PREVIEW: 'maker_preview',
@@ -321,6 +325,19 @@ const useEventTracker = () => {
321
325
  is_enabled: isEnabled,
322
326
  });
323
327
  },
328
+ // Undo / Redo (BP-5506)
329
+ sendUndoEvent: (props) => {
330
+ _publishEvent(EVENTS.WEBSITE_MAKER_UNDO, props);
331
+ },
332
+ sendRedoEvent: (props) => {
333
+ _publishEvent(EVENTS.WEBSITE_MAKER_REDO, props);
334
+ },
335
+ sendHistoryCappedEvent: (props) => {
336
+ _publishEvent(EVENTS.WEBSITE_MAKER_HISTORY_CAPPED, props);
337
+ },
338
+ sendHistoryOversizedEvent: (props) => {
339
+ _publishEvent(EVENTS.WEBSITE_MAKER_HISTORY_OVERSIZED, props);
340
+ },
324
341
  };
325
342
  };
326
343
  export { useEventTracker };
@@ -0,0 +1,17 @@
1
+ import { type ComputedRef } from 'vue';
2
+ /**
3
+ * Returns whether undo/redo is active for the current maker session. All
4
+ * three conditions must hold:
5
+ *
6
+ * 1. `userStore.features.canUseUndoRedo` is true. The flag is populated by
7
+ * the consumer (BrandCrowd.Net / web-renderer) via the
8
+ * `WebsiteDesignUserFeatures.CanUseUndoRedo` boolean on the ViewModel —
9
+ * same precedent as RichTextEditor / GettyVideos / AITextGenerator.
10
+ * 2. The maker is a brand-site (Website Maker). V1 scope is brand-site
11
+ * only; brand-page (single-page profile) and brand-contact (vCard) are
12
+ * out of scope.
13
+ * 3. The session is NOT in admin-maker mode (`userStore.isAdmin`). The
14
+ * admin maker uses the same components but a different editing flow
15
+ * (template authoring) where undo/redo is out of scope.
16
+ */
17
+ export declare function useUndoRedoFlag(): ComputedRef<boolean>;
@@ -0,0 +1,25 @@
1
+ import { computed } from 'vue';
2
+ import { useBrandPageMakerUserStore } from '@brand-page-maker/stores/user';
3
+ import { useBrandPageMakerStore } from '@brand-page-maker/stores/brandpage-maker/brandpage-maker-store';
4
+ /**
5
+ * Returns whether undo/redo is active for the current maker session. All
6
+ * three conditions must hold:
7
+ *
8
+ * 1. `userStore.features.canUseUndoRedo` is true. The flag is populated by
9
+ * the consumer (BrandCrowd.Net / web-renderer) via the
10
+ * `WebsiteDesignUserFeatures.CanUseUndoRedo` boolean on the ViewModel —
11
+ * same precedent as RichTextEditor / GettyVideos / AITextGenerator.
12
+ * 2. The maker is a brand-site (Website Maker). V1 scope is brand-site
13
+ * only; brand-page (single-page profile) and brand-contact (vCard) are
14
+ * out of scope.
15
+ * 3. The session is NOT in admin-maker mode (`userStore.isAdmin`). The
16
+ * admin maker uses the same components but a different editing flow
17
+ * (template authoring) where undo/redo is out of scope.
18
+ */
19
+ export function useUndoRedoFlag() {
20
+ const userStore = useBrandPageMakerUserStore();
21
+ const brandPageMakerStore = useBrandPageMakerStore();
22
+ return computed(() => userStore.features.canUseUndoRedo &&
23
+ brandPageMakerStore.isBrandSite &&
24
+ !userStore.isAdmin);
25
+ }
@@ -177,16 +177,55 @@ export declare const useBrandPageMakerStore: import("pinia").StoreDefinition<"br
177
177
  hideChangeTemplateConfirmModal(): void;
178
178
  onBackgroundChanged(): void;
179
179
  onChangeTemplateConfirmModalCancel(): void;
180
- onChangeTemplateConfirmModalConfirm(): void;
180
+ onChangeTemplateConfirmModalConfirm(): Promise<void>;
181
181
  onContentChanged(): void;
182
182
  onStyleChanged(): void;
183
- onTemplateSelected(payload: OnTemplateSelectedPayload): void;
183
+ onTemplateSelected(payload: OnTemplateSelectedPayload): Promise<void>;
184
184
  setSelectedTabName(payload: any): void;
185
185
  showNextNotificationMessage(): Promise<void>;
186
186
  updateContent<TContent extends Content, P extends {
187
187
  id: string;
188
188
  content: TContent;
189
189
  }>(payload: P): Promise<void>;
190
+ /**
191
+ * Restore every store that the `brandPageData` getter reads from, so undo
192
+ * and redo bring back the EXACT document state captured at snapshot time.
193
+ *
194
+ * `initialiseStoresByBrandPageModelAsync` is too narrow for undo/redo — it
195
+ * only rehydrates pages, sections, and nav structure, which is enough for
196
+ * the AI-apply path but leaves navigation styles, backgrounds, button/text/
197
+ * logo/gallery styles, shop config, and several own-store fields unchanged.
198
+ * This action mirrors the full hydration surface of `applySelectedTemplate`
199
+ * (minus the template-specific logo/personalisation logic) so a restore is
200
+ * a complete round-trip of what `brandPageData` returns.
201
+ *
202
+ * Called ONLY by history-store during undo/redo. The history store sets
203
+ * `isApplyingSnapshot=true` across this call to prevent the deep-watcher
204
+ * on `brandPageData` from re-capturing the restored state.
205
+ */
206
+ /**
207
+ * Force-commit a `template_switch` entry to the history store, if the
208
+ * history store has a baseline (which only happens when the undo/redo
209
+ * feature flag is on — see `BrandPageMaker.mixin.ts`).
210
+ */
211
+ _captureTemplateSwitchIfEnabled(): void;
212
+ applyHistorySnapshot(snapshot: BrandPageModel, activePageId?: string, logoEditsStr?: string): Promise<void>;
213
+ _syncLogoSettingsFromSnapshot(snapshot: BrandPageModel, logoEditsStr?: string): Promise<void>;
214
+ /**
215
+ * Restore the active page after a history apply. The id passed in is
216
+ * already validated against the restored nav by the history store; if
217
+ * it's undefined (no entry walking back had a viable page), fall back
218
+ * to the first/default route so the URL, `routeStore.currentRoute.params`,
219
+ * `pageNavigation.activePageId`, and the page-tab highlight all line up.
220
+ *
221
+ * `setCurrentActivePage` is called explicitly in addition to
222
+ * `navigateToPageByPageId` because `navigateToPageByPageId` is a no-op
223
+ * when the router instance is undefined (e.g. SSR / unit tests), but the
224
+ * Pinia state must still be updated so the sidebar's `currentPage`
225
+ * getter returns the right page.
226
+ */
227
+ _navigateToActivePage(activePageId?: string): void;
228
+ _fallbackSidebarIfSelectedContentMissing(snapshot: BrandPageModel): void;
190
229
  export(): BrandPageModel;
191
230
  setBrandPageType({ brandPageType }: {
192
231
  brandPageType: BrandPageType;