@designcrowd/library.brand-page 5.18.1-undo-29 → 5.18.1-undo-32

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 (46) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-BxL6mTJW.js → CreatedOnBrandCrowd-de-de-DUgkmx89.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-BPbjqfkj.js → CreatedOnBrandCrowd-en-us-C5dQGLuA.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-DDsoe143.js → CreatedOnBrandCrowd-es-es-CjPcnNlq.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-Dak7ppy_.js → CreatedOnBrandCrowd-fr-ca-D2wnZOOE.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-Dak7ppy_.js → CreatedOnBrandCrowd-fr-fr-D2wnZOOE.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-BUAneEVD.js → CreatedOnBrandCrowd-pt-br-OQj-IBh_.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-BUAneEVD.js → CreatedOnBrandCrowd-pt-pt-OQj-IBh_.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-BJ00bTz_.js → CreatedOnDcom-de-de-DLijuIaL.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-B0V1M9Hs.js → CreatedOnDcom-en-us-D9M_heGE.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-YDMLB7u6.js → CreatedOnDcom-es-es-PgWwbBLA.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-DppQ26s1.js → CreatedOnDcom-fr-ca-BXiB-abj.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-0Xi-3slB.js → CreatedOnDcom-fr-fr-BXhTmu7F.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-De-wHqSu.js → CreatedOnDcom-pt-br-3e6y567w.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-CQGAsn5D.js → CreatedOnDcom-pt-pt-GojOtHmO.js} +1 -1
  15. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +1 -1
  16. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +1 -1
  17. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +1 -1
  18. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +1 -1
  19. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +1 -1
  20. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +1 -1
  21. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +1 -1
  22. package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +1 -1
  23. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +1 -1
  24. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +1 -1
  25. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +46 -22
  26. package/lib/src/brand-page-maker/stores/history/history-store.js +66 -66
  27. package/lib/src/index.mjs +1 -1
  28. package/lib/src/{lib-YRlMax_i.js → lib-DVs3jUit.js} +18674 -18654
  29. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +65 -1
  30. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +12 -0
  31. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +1 -1
  32. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +1 -1
  33. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +1 -0
  34. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +2 -1
  35. package/lib/src/shared/logo-settings/store/editable-logo-store.d.ts +14 -0
  36. package/lib/src/shared/logo-settings/store/editable-logo-store.js +26 -10
  37. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +1 -1
  38. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +2 -1
  39. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +1 -1
  40. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +1 -1
  41. package/package.json +1 -1
  42. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +53 -23
  43. package/src/brand-page-maker/stores/history/history-store.test.ts +29 -135
  44. package/src/brand-page-maker/stores/history/history-store.ts +85 -76
  45. package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +12 -0
  46. package/src/shared/logo-settings/store/editable-logo-store.ts +28 -11
@@ -1,13 +1,12 @@
1
1
  import { defineStore } from 'pinia';
2
- import { computed, nextTick, ref, shallowRef, toRaw, watch } from 'vue';
2
+ import { computed, ref, shallowRef, toRaw, watch } from 'vue';
3
3
  import type { BrandPageModel } from '@brand-page';
4
4
  import { useBrandPageMakerStore } from '../brandpage-maker/brandpage-maker-store';
5
+ import { useBrandPageContainerStore } from '../brandpage-container';
5
6
  import { useAiWebsiteBuilderThreadStore } from '../ai-thread/ai-website-builder-thread-store';
6
7
  import { useEventTracker } from '../../composables/useEventTracker';
7
8
  import { usePageNavigationStore } from '@shared/page-navigation/store/page-navigation-store';
8
9
  import { useUiEditableLogoStore } from '@shared/logo-settings/store/editable-logo-store';
9
- import { useShopConfigStore } from '@shared/ecommerce-settings/store/shop-settings-store';
10
- import { useUiPageSettingsStore } from '@shared/page-settings/store';
11
10
 
12
11
  /**
13
12
  * A single history entry.
@@ -121,23 +120,6 @@ const MAX_ENTRY_BYTES = 25 * 1024 * 1024;
121
120
  // that would otherwise make undo light up before the user has done anything.
122
121
  const BASELINE_SETTLE_MS = 2000;
123
122
 
124
- // Content-level wrapper keys whose `paymentConfig` child is a denormalised
125
- // cache of `shopConfigStore.paymentConfig` (the user's Stripe Connect
126
- // linkage). Stripe Connect linkage state is backend-confirmed (per
127
- // `project-guardrails.md`) and must NEVER ride along on the undo/redo stack.
128
- //
129
- // paymentConfig is kept invariant under undo/redo by re-stamping every live
130
- // wrapper from `shopConfigStore.paymentConfig` after every restore — see
131
- // `restorePaymentConfigsOnLivePages`. The shop store itself is never
132
- // touched by undo/redo (see `applyHistorySnapshot` step 6), so the live
133
- // wrapper always equals the live shop store regardless of what's in the
134
- // snapshot bytes.
135
- const PAYMENT_CONFIG_WRAPPER_KEYS = [
136
- 'supportMeConfig',
137
- 'requestPaymentConfig',
138
- 'shopPaymentConfig',
139
- ] as const;
140
-
141
123
  export const useHistoryStore = defineStore('history', () => {
142
124
  const eventTracker = useEventTracker();
143
125
 
@@ -172,6 +154,65 @@ export const useHistoryStore = defineStore('history', () => {
172
154
  */
173
155
  let cachedMakerStore: ReturnType<typeof useBrandPageMakerStore> | null = null;
174
156
 
157
+ /**
158
+ * Walk `brandPageData` and null `logoImageBase64Url` on every logo
159
+ * placement (header/footer × desktop/mobile + per-page logo content).
160
+ * Pre-purchase only — the same gate the save path uses
161
+ * (see `brand-page-container-store.ts:805`).
162
+ *
163
+ * Each rendered base64 is ~2-4 MB and the brand-site templates put the
164
+ * same logo in 6-8 places, so unstripped pre-purchase snapshots run
165
+ * 18-24 MB and bump the 25 MB per-entry cap, which silently drops the
166
+ * entry. The base64 is repopulated on undo by `_syncLogoSettingsFromSnapshot`
167
+ * (designed: re-issue fabric-render; BYO: stamp from per-token cache),
168
+ * so the snapshot doesn't need to carry it.
169
+ */
170
+ function stripLogoBase64IfPrePurchase(data: {
171
+ pages?: { contents?: { logoImageBase64Url?: string }[] }[];
172
+ pageHeaderDesktop?: { logoImageBase64Url?: string };
173
+ pageHeaderMobile?: { logoImageBase64Url?: string };
174
+ pageFooterDesktop?: { logoImageBase64Url?: string };
175
+ pageFooterMobile?: { logoImageBase64Url?: string };
176
+ }): void {
177
+ try {
178
+ if (!useBrandPageContainerStore().isPrePurchase) return;
179
+ } catch {
180
+ return;
181
+ }
182
+
183
+ if (data.pageHeaderDesktop) {
184
+ data.pageHeaderDesktop.logoImageBase64Url = undefined;
185
+ }
186
+
187
+ if (data.pageHeaderMobile) {
188
+ data.pageHeaderMobile.logoImageBase64Url = undefined;
189
+ }
190
+
191
+ if (data.pageFooterDesktop) {
192
+ data.pageFooterDesktop.logoImageBase64Url = undefined;
193
+ }
194
+
195
+ if (data.pageFooterMobile) {
196
+ data.pageFooterMobile.logoImageBase64Url = undefined;
197
+ }
198
+
199
+ if (Array.isArray(data.pages)) {
200
+ for (const page of data.pages) {
201
+ if (!Array.isArray(page?.contents)) continue;
202
+
203
+ for (const content of page.contents) {
204
+ if (
205
+ content &&
206
+ typeof content === 'object' &&
207
+ 'logoImageBase64Url' in content
208
+ ) {
209
+ content.logoImageBase64Url = undefined;
210
+ }
211
+ }
212
+ }
213
+ }
214
+ }
215
+
175
216
  /**
176
217
  * Serialize the current `brandPageData` into a detached JSON string.
177
218
  * Synchronous — safe to call inside a microtask without racing a follow-up
@@ -181,7 +222,13 @@ export const useHistoryStore = defineStore('history', () => {
181
222
  if (!cachedMakerStore) return null;
182
223
 
183
224
  try {
184
- return JSON.stringify(toRaw(cachedMakerStore.brandPageData));
225
+ const cloned = JSON.parse(
226
+ JSON.stringify(toRaw(cachedMakerStore.brandPageData)),
227
+ );
228
+
229
+ stripLogoBase64IfPrePurchase(cloned);
230
+
231
+ return JSON.stringify(cloned);
185
232
  } catch (error) {
186
233
  console.error('history-store: failed to serialize snapshot', error);
187
234
 
@@ -276,7 +323,20 @@ export const useHistoryStore = defineStore('history', () => {
276
323
  }): 'committed' | 'oversized' | 'noop' {
277
324
  const current = entries.value[currentIndex.value];
278
325
 
279
- if (current && current.snapshot === args.snapshot) return 'noop';
326
+ // Compare both the snapshot bytes AND the logoEdits sidecar.
327
+ // Pre-purchase logo-tab edits (text/color/font) live in the
328
+ // `editableLogoStore.logoEdits` sidecar, NOT in `brandPageData`.
329
+ // The accompanying base64 writeback is also stripped from the
330
+ // snapshot (size cap), so a pure logo edit would produce a
331
+ // byte-identical snapshot to the previous entry — without the
332
+ // sidecar comparison every logo edit would dedup as a no-op.
333
+ if (
334
+ current &&
335
+ current.snapshot === args.snapshot &&
336
+ current.logoEdits === args.logoEdits
337
+ ) {
338
+ return 'noop';
339
+ }
280
340
 
281
341
  if (args.snapshot.length > MAX_ENTRY_BYTES) {
282
342
  eventTracker.sendHistoryOversizedEvent({
@@ -571,9 +631,9 @@ export const useHistoryStore = defineStore('history', () => {
571
631
  * dedicated `applyHistorySnapshot` action, which rehydrates every Pinia
572
632
  * source store + own-store scalar fields that `brandPageData` reads from.
573
633
  *
574
- * Holds `isApplyingSnapshot` through `nextTick` so Vue's reactive queue
575
- * drains while the watcher guard is still set, preventing the restore from
576
- * being re-captured as a spurious duplicate entry.
634
+ * Holds `isApplyingSnapshot` for the duration of the apply so the
635
+ * watcher guard suppresses the cascade of mutations from being
636
+ * re-captured as a spurious duplicate entry.
577
637
  *
578
638
  * Active-page resolution priority:
579
639
  * 1. Diff against `cameFromIndex` — any page present in the target
@@ -671,62 +731,11 @@ export const useHistoryStore = defineStore('history', () => {
671
731
  resolvedActivePageId,
672
732
  targetEntry?.logoEdits,
673
733
  );
674
- await nextTick();
675
-
676
- // Re-stamp `wrapper.paymentConfig` on every payment-config wrapper in
677
- // the freshly-restored content tree from the live shop store. Stripe
678
- // Connect linkage is backend-confirmed (per `project-guardrails.md`)
679
- // and must NEVER come from the snapshot — the captured value can be
680
- // arbitrarily stale (an entry captured before
681
- // `PaymentConfigField.mixin.ts:created()` lazily filled in the
682
- // wrapper carries `paymentConfig: undefined`) and using it would
683
- // re-surface the "Please enable a payment provider" warning on
684
- // undo. The shop store's value is itself never undoable (see
685
- // `applyHistorySnapshot` step 6).
686
- restorePaymentConfigsOnLivePages();
687
734
  } finally {
688
735
  isApplyingSnapshot.value = false;
689
736
  }
690
737
  }
691
738
 
692
- /**
693
- * Walk the live `pageSettingsStore.pages` and stamp
694
- * `wrapper.paymentConfig = shopConfigStore.paymentConfig` on every
695
- * payment-config wrapper. Called from `applySnapshotString` after
696
- * `applyHistorySnapshot` rebuilds page contents.
697
- */
698
- function restorePaymentConfigsOnLivePages(): void {
699
- try {
700
- const shopStore = useShopConfigStore();
701
- const pageSettingsStore = useUiPageSettingsStore();
702
- const livePaymentConfig = shopStore.paymentConfig;
703
-
704
- for (const page of pageSettingsStore.pages) {
705
- for (const item of page.contents) {
706
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
707
- const content: any = item.settings.content;
708
-
709
- for (const key of PAYMENT_CONFIG_WRAPPER_KEYS) {
710
- const wrapper = content?.[key];
711
-
712
- if (
713
- wrapper &&
714
- typeof wrapper === 'object' &&
715
- !Array.isArray(wrapper)
716
- ) {
717
- wrapper.paymentConfig = livePaymentConfig;
718
- }
719
- }
720
- }
721
- }
722
- } catch (error) {
723
- console.error(
724
- 'history-store: failed to restore paymentConfig on live pages',
725
- error,
726
- );
727
- }
728
- }
729
-
730
739
  /** Move the pointer back one step and apply the entry at the new position. */
731
740
  async function undo(): Promise<void> {
732
741
  if (!canUndo.value) return;
@@ -29,6 +29,7 @@ import {
29
29
  } from '@brand-page-maker/utils';
30
30
  import { useUiStyleSettingsStore } from '../../../style-settings/store';
31
31
  import { usePageNavigationStore } from '../../../../shared/page-navigation/store/page-navigation-store';
32
+ import { useHistoryStore } from '@brand-page-maker/stores/history/history-store';
32
33
 
33
34
  interface CategoryTab {
34
35
  category: string;
@@ -44,6 +45,7 @@ export default defineComponent({
44
45
  const styleSettingsStore = useUiStyleSettingsStore();
45
46
  const userStore = useBrandPageMakerUserStore();
46
47
  const eventTracker = useEventTracker();
48
+ const historyStore = useHistoryStore();
47
49
  const { externalEditor } = useExternalRichTextEditor();
48
50
 
49
51
  return {
@@ -65,6 +67,7 @@ export default defineComponent({
65
67
  pageSettingsStore,
66
68
  styleSettingsStore,
67
69
  eventTracker,
70
+ historyStore,
68
71
  externalEditor,
69
72
  };
70
73
  },
@@ -81,6 +84,15 @@ export default defineComponent({
81
84
  },
82
85
  mounted() {
83
86
  if (this.canUseRichTextEditor) {
87
+ // `switchAllContentToRTE` walks every content item on every page
88
+ // and rewraps plain-text titles/paragraphs in TipTap HTML so they
89
+ // render through the inline RTE. That's a hydration write — it
90
+ // happens whenever the Content sidebar tab mounts (incl. when the
91
+ // user clicks the header in the canvas) and produces no
92
+ // user-visible change. Arm the merge flag so the watcher folds
93
+ // the resulting flush into the current head entry instead of
94
+ // pushing a phantom undo step.
95
+ this.historyStore.mergeNextMutation();
84
96
  switchAllContentToRTE(
85
97
  this.pageSettingsStore,
86
98
  this.externalEditor,
@@ -413,6 +413,34 @@ export const useUiEditableLogoStore = defineStore('uiEditableLogo', {
413
413
 
414
414
  await Promise.all(tasks);
415
415
 
416
+ this.stampLogoBase64IntoBrandPageData(overrideLogoVariation);
417
+
418
+ // Stash the freshly rendered variation set under the active draft
419
+ // token so undo can restore it later without re-rendering. This is
420
+ // the only place in production that meaningfully populates
421
+ // `editableLogoVariations` (BYO upload + designed-logo setStateAsync
422
+ // both funnel here), so caching here keeps every distinct draft's
423
+ // grid available for the lifetime of the session.
424
+ if (this.logoDraftToken) {
425
+ this.variationsByDraftToken[this.logoDraftToken] =
426
+ this.editableLogoVariations.map((v) => ({ ...v }));
427
+ }
428
+ },
429
+
430
+ /**
431
+ * Stamp `editableLogoVariations[*].base64` across every consumer in
432
+ * `brandPageData`: header/footer logo sections (desktop + mobile)
433
+ * and every `LogoContent` block on every page. Used by the live edit
434
+ * path after a fabric-render POST AND by the undo/redo BYO branch
435
+ * after `restoreVariationsForDraftToken` has rehydrated the cache.
436
+ *
437
+ * The history store strips `logoImageBase64Url` from snapshots to
438
+ * keep them under the 25 MB per-entry cap, so something has to
439
+ * write the base64 back into `brandPageData` after restore — for
440
+ * designed logos it's the awaited fabric-render call; for BYO it's
441
+ * this method.
442
+ */
443
+ stampLogoBase64IntoBrandPageData(overrideLogoVariation?: number): void {
416
444
  const pageSettingStore = useUiPageSettingsStore();
417
445
 
418
446
  [PAGE_SECTIONS.header, PAGE_SECTIONS.footer].forEach((section) => {
@@ -449,17 +477,6 @@ export const useUiEditableLogoStore = defineStore('uiEditableLogo', {
449
477
  }
450
478
  });
451
479
  });
452
-
453
- // Stash the freshly rendered variation set under the active draft
454
- // token so undo can restore it later without re-rendering. This is
455
- // the only place in production that meaningfully populates
456
- // `editableLogoVariations` (BYO upload + designed-logo setStateAsync
457
- // both funnel here), so caching here keeps every distinct draft's
458
- // grid available for the lifetime of the session.
459
- if (this.logoDraftToken) {
460
- this.variationsByDraftToken[this.logoDraftToken] =
461
- this.editableLogoVariations.map((v) => ({ ...v }));
462
- }
463
480
  },
464
481
 
465
482
  /**