@designcrowd/library.brand-page 5.17.25-undo-12 → 5.17.25-undo-14

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 (31) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-4mxqeHPP.js → CreatedOnBrandCrowd-de-de-D0AQ4h1Y.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-DQN_hGjC.js → CreatedOnBrandCrowd-en-us-Bz9D9FcQ.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-gijtJMPK.js → CreatedOnBrandCrowd-es-es-B6EKNEDx.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-BcOADD0V.js → CreatedOnBrandCrowd-fr-ca-DvC5JIAW.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-BcOADD0V.js → CreatedOnBrandCrowd-fr-fr-DvC5JIAW.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-B5eEyjAo.js → CreatedOnBrandCrowd-pt-br-tckhI2rl.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-B5eEyjAo.js → CreatedOnBrandCrowd-pt-pt-tckhI2rl.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-DSGP6AAT.js → CreatedOnDcom-de-de-BJAmW8nU.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-BOuoJM_x.js → CreatedOnDcom-en-us-0IxL5rtr.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-kbiGFyBV.js → CreatedOnDcom-es-es-j1tEaAuh.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-BVFxrE6-.js → CreatedOnDcom-fr-ca-BHD4nfCD.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-92xJGi0w.js → CreatedOnDcom-fr-fr-D4b447yE.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-C40X9FAV.js → CreatedOnDcom-pt-br-6WIaKLxK.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-CXxJUTUx.js → CreatedOnDcom-pt-pt-DSvzJLxn.js} +1 -1
  15. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +22 -8
  16. package/lib/src/brand-page-maker/stores/history/history-store.d.ts +6 -0
  17. package/lib/src/brand-page-maker/stores/history/history-store.js +10 -9
  18. package/lib/src/brand-page-maker/stores/logo-store/logo-store.d.ts +1 -0
  19. package/lib/src/index.mjs +1 -1
  20. package/lib/src/{lib-DaFVTyb9.js → lib-3NPiNYNp.js} +27 -17
  21. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +2 -0
  22. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +2 -0
  23. package/lib/src/shared/logo-settings/store/editable-logo-store.d.ts +9 -1
  24. package/lib/src/shared/logo-settings/store/editable-logo-store.js +33 -0
  25. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +2 -0
  26. package/package.json +1 -1
  27. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +26 -10
  28. package/src/brand-page-maker/stores/history/history-store.test.ts +5 -5
  29. package/src/brand-page-maker/stores/history/history-store.ts +16 -10
  30. package/src/brand-page-maker/stores/logo-store/logo-store.ts +5 -0
  31. package/src/shared/logo-settings/store/editable-logo-store.ts +45 -1
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DaFVTyb9.js";
2
+ import { _ as t } from "./lib-3NPiNYNp.js";
3
3
  const i = {}, h = {
4
4
  width: "275",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DaFVTyb9.js";
2
+ import { _ as t } from "./lib-3NPiNYNp.js";
3
3
  const i = {}, h = {
4
4
  width: "251",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DaFVTyb9.js";
2
+ import { _ as t } from "./lib-3NPiNYNp.js";
3
3
  const i = {}, h = {
4
4
  width: "250",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DaFVTyb9.js";
2
+ import { _ as t } from "./lib-3NPiNYNp.js";
3
3
  const i = {}, h = {
4
4
  width: "237",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DaFVTyb9.js";
2
+ import { _ as t } from "./lib-3NPiNYNp.js";
3
3
  const i = {}, h = {
4
4
  width: "237",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DaFVTyb9.js";
2
+ import { _ as t } from "./lib-3NPiNYNp.js";
3
3
  const i = {}, h = {
4
4
  width: "263",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DaFVTyb9.js";
2
+ import { _ as t } from "./lib-3NPiNYNp.js";
3
3
  const i = {}, h = {
4
4
  width: "263",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-DaFVTyb9.js";
2
+ import { _ as e } from "./lib-3NPiNYNp.js";
3
3
  const M = {}, Z = {
4
4
  width: "242",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-DaFVTyb9.js";
2
+ import { _ as e } from "./lib-3NPiNYNp.js";
3
3
  const i = {}, M = {
4
4
  width: "231",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-DaFVTyb9.js";
2
+ import { _ as e } from "./lib-3NPiNYNp.js";
3
3
  const M = {}, Z = {
4
4
  width: "230",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-DaFVTyb9.js";
2
+ import { _ as e } from "./lib-3NPiNYNp.js";
3
3
  const i = {}, l = {
4
4
  width: "216",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-DaFVTyb9.js";
2
+ import { _ as e } from "./lib-3NPiNYNp.js";
3
3
  const i = {}, l = {
4
4
  width: "216",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as M } from "./lib-DaFVTyb9.js";
2
+ import { _ as M } from "./lib-3NPiNYNp.js";
3
3
  const Z = {}, e = {
4
4
  width: "232",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as M } from "./lib-DaFVTyb9.js";
2
+ import { _ as M } from "./lib-3NPiNYNp.js";
3
3
  const Z = {}, e = {
4
4
  width: "232",
5
5
  height: "36",
@@ -567,6 +567,9 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
567
567
  // restored header logo. The preview rehydrates via the page contents,
568
568
  // but `uiLogoSettings` holds its own copy that drives the sidebar
569
569
  // "current logo" state — same pattern as `initialiseStoresByBrandPageModelAsync`.
570
+ // Also restores the variations grid + template asset for the
571
+ // snapshot's draft token (both are sidecars to `brandPageData` —
572
+ // BYO upload mutates them out of band).
570
573
  this._syncLogoSettingsFromSnapshot(snapshot);
571
574
  // 9. If the sidebar is editing a content item that no longer exists in
572
575
  // the restored page, fall back to the Content tab so the user doesn't
@@ -585,15 +588,26 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
585
588
  logoSettingsStore.setState({
586
589
  newState: { selectedLogoImage: logoImage },
587
590
  });
588
- // Re-derive `enableEditMode` so the sidebar's design/upload tabs
589
- // reflect the restored logo. BYO logos can't be edited in the design
590
- // surface, so `enableEditMode` must flip false on undo back to a BYO
591
- // upload and true on redo back to a designed logo. Logo drafts are
592
- // append-only during a session, so a token in the snapshot always
593
- // resolves here.
594
- const draft = logoStore.getLogoDraftAssetByToken(logoImage.logoDraftToken);
595
- if (draft)
591
+ const draftToken = logoImage.logoDraftToken;
592
+ if (!draftToken)
593
+ return;
594
+ // Re-derive `enableEditMode` and the active template asset from the
595
+ // logo-store's draft registry. Drafts are append-only for the session,
596
+ // and BYO upload stamps `templateAsset` onto the registered draft when
597
+ // it lands — so the registered draft is enough to fully restore the
598
+ // sidebar's design/upload chooser without storing anything inside
599
+ // each history entry. The variations grid is restored from the
600
+ // editable-logo store's per-token cache (populated by every
601
+ // `updateEditableLogoImageUrlAsync` render).
602
+ const draft = logoStore.getLogoDraftAssetByToken(draftToken);
603
+ if (draft) {
596
604
  editableLogoStore.setEnableEditMode(!draft.isByo);
605
+ if (draft.templateAsset) {
606
+ logoStore.setLogoTemplateAsset(draft.templateAsset);
607
+ }
608
+ }
609
+ editableLogoStore.setLogoDraftToken(draftToken);
610
+ editableLogoStore.restoreVariationsForDraftToken(draftToken);
597
611
  },
598
612
  _fallbackSidebarIfSelectedContentMissing(snapshot) {
599
613
  const contentSettingsStore = useUiContentSettingsStore();
@@ -8,6 +8,12 @@
8
8
  * with the live store.
9
9
  * 2. `sizeBytes === snapshot.length` is automatic and accurate for the V2
10
10
  * memory-budget instrumentation.
11
+ *
12
+ * Sidecar state that doesn't live on `brandPageData` (the variations grid in
13
+ * the Logo sidebar, the active `logoTemplateAsset`, the active
14
+ * `logoDraftToken`) is restored on undo by `_syncLogoSettingsFromSnapshot`
15
+ * via per-draft-token caches on the logo / editable-logo stores — keyed off
16
+ * `logoImage.logoDraftToken` which IS in the snapshot.
11
17
  */
12
18
  export interface HistoryEntry {
13
19
  /** JSON.stringify(BrandPageModel) at the moment of capture. */
@@ -32,8 +32,10 @@ const CAPTURE_MAX_WAIT_MS = 10000;
32
32
  // FR-12: 40-entry cap. FR-13: 100 MB memory budget. FR-13c: per-entry
33
33
  // oversize threshold — entries above this are skipped + emit telemetry.
34
34
  // 25 MB accommodates a high-res BYO logo upload, which renders ~2.5 MB
35
- // of base64 PNG into each of four viewport sections (~10 MB) plus
36
- // per-page logo content blocks. The 100 MB total budget still evicts
35
+ // of base64 PNG into each of four viewport sections (~10 MB) plus per-page
36
+ // logo content blocks. The variations grid (~10 MB) does NOT live in the
37
+ // snapshot — it sits on the editable-logo store keyed by draft token, and
38
+ // is restored on undo from there. The 100 MB total budget still evicts
37
39
  // oldest non-baseline entries to keep memory bounded.
38
40
  const MAX_ENTRIES = 40;
39
41
  const MAX_MEMORY_BYTES = 100 * 1024 * 1024;
@@ -72,15 +74,14 @@ export const useHistoryStore = defineStore('history', () => {
72
74
  * Synchronous — safe to call inside a microtask without racing a follow-up
73
75
  * mutation.
74
76
  */
75
- function serializeCurrentBrandPageData() {
77
+ function serializeCurrentSnapshot() {
76
78
  if (!cachedMakerStore)
77
79
  return null;
78
80
  try {
79
- const raw = toRaw(cachedMakerStore.brandPageData);
80
- return JSON.stringify(raw);
81
+ return JSON.stringify(toRaw(cachedMakerStore.brandPageData));
81
82
  }
82
83
  catch (error) {
83
- console.error('history-store: failed to serialize brandPageData', error);
84
+ console.error('history-store: failed to serialize snapshot', error);
84
85
  return null;
85
86
  }
86
87
  }
@@ -519,7 +520,7 @@ export const useHistoryStore = defineStore('history', () => {
519
520
  return;
520
521
  if (!baselineCaptured.value)
521
522
  return;
522
- const snapshot = serializeCurrentBrandPageData();
523
+ const snapshot = serializeCurrentSnapshot();
523
524
  if (!snapshot)
524
525
  return;
525
526
  // During the post-init settle window, fold any captured mutation back
@@ -571,7 +572,7 @@ export const useHistoryStore = defineStore('history', () => {
571
572
  if (baselineCaptured.value)
572
573
  return;
573
574
  installWatcher();
574
- const snapshot = serializeCurrentBrandPageData();
575
+ const snapshot = serializeCurrentSnapshot();
575
576
  if (!snapshot)
576
577
  return;
577
578
  // Baseline starts a fresh stack of exactly 1 entry with pointer at 0.
@@ -601,7 +602,7 @@ export const useHistoryStore = defineStore('history', () => {
601
602
  return 'skipped';
602
603
  if (!baselineCaptured.value)
603
604
  return 'skipped';
604
- const snapshot = serializeCurrentBrandPageData();
605
+ const snapshot = serializeCurrentSnapshot();
605
606
  if (!snapshot)
606
607
  return 'skipped';
607
608
  return commitEntry({ snapshot, ...args });
@@ -10,6 +10,7 @@ export interface LogoDraftAsset {
10
10
  tick: number;
11
11
  isByo: boolean;
12
12
  logoEditUrl?: string;
13
+ templateAsset?: LogoTemplateAsset;
13
14
  }
14
15
  export interface LogoStoreState {
15
16
  logoTemplateAsset?: LogoTemplateAsset;
package/lib/src/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as E, a as T, b as s, c as I, d as S, e as N, f as e, B as A, g as O, h as C, i as G, j as D, k as P, l as t, m as R, n as L, o as M, p as o, q as r, r as b, s as n, t as F, u as i, v as l, w as g, x as B, y as c, z as Y, C as U, D as d, E as u, F as H, G as p, H as y, I as K, J as k, K as m, L as V, M as X, N as h, O as v, P as W, Q as f, R as x, S as z, T as w, U as Z, V as j, W as Q, X as q, Y as J, Z as $, $ as aa, a0 as _a, a1 as Ea, a2 as Ta, a3 as sa, a4 as Ia, a5 as Sa, a6 as Na, a7 as ea, a8 as Aa, a9 as Oa, aa as Ca, ab as Ga, ac as Da, ad as Pa, ae as ta, af as Ra, ag as La, ah as Ma, ai as oa, aj as ra, ak as ba, al as na, am as Fa, an as ia, ao as la, ap as ga, aq as Ba, ar as ca, as as Ya, at as Ua, au as da, av as ua, aw as Ha, ax as pa, ay as ya, az as Ka, aA as ka, aB as ma, aC as Va, aD as Xa, aE as ha, aF as va, aG as Wa, aH as fa, aI as xa, aJ as za, aK as wa, aL as Za, aM as ja, aN as Qa, aO as qa, aP as Ja, aQ as $a, aR as a_, aS as __, aT as E_, aU as T_, aV as s_, aW as I_, aX as S_, aY as N_, aZ as e_, a_ as A_, a$ as O_, b0 as C_, b1 as G_, b2 as D_, b3 as P_, b4 as t_, b5 as R_, b6 as L_, b7 as M_, b8 as o_, b9 as r_, ba as b_, bb as n_, bc as F_, bd as i_, be as l_, bf as g_, bg as B_, bh as c_, bi as Y_, bj as U_, bk as d_, bl as u_, bm as H_, bn as p_, bo as y_, bp as K_, bq as k_, br as m_, bs as V_, bt as X_, bu as h_, bv as v_, bw as W_, bx as f_, by as x_, bz as z_, bA as w_, bB as Z_, bC as j_, bD as Q_, bE as q_, bF as J_, bG as $_, bH as aE, bI as _E, bJ as EE, bK as TE, bL as sE, bM as IE, bN as SE, bO as NE, bP as eE, bQ as AE, bR as OE, bS as CE, bT as GE, bU as DE, bV as PE, bW as tE, bX as RE, bY as LE, bZ as ME, b_ as oE, b$ as rE, c0 as bE, c1 as nE, c2 as FE, c3 as iE, c4 as lE, c5 as gE, c6 as BE, c7 as cE, c8 as YE, c9 as UE, ca as dE, cb as uE, cc as HE, cd as pE, ce as yE, cf as KE, cg as kE, ch as mE, ci as VE, cj as XE, ck as hE, cl as vE, cm as WE, cn as fE, co as xE } from "./lib-DaFVTyb9.js";
1
+ import { A as E, a as T, b as s, c as I, d as S, e as N, f as e, B as A, g as O, h as C, i as G, j as D, k as P, l as t, m as R, n as L, o as M, p as o, q as r, r as b, s as n, t as F, u as i, v as l, w as g, x as B, y as c, z as Y, C as U, D as d, E as u, F as H, G as p, H as y, I as K, J as k, K as m, L as V, M as X, N as h, O as v, P as W, Q as f, R as x, S as z, T as w, U as Z, V as j, W as Q, X as q, Y as J, Z as $, $ as aa, a0 as _a, a1 as Ea, a2 as Ta, a3 as sa, a4 as Ia, a5 as Sa, a6 as Na, a7 as ea, a8 as Aa, a9 as Oa, aa as Ca, ab as Ga, ac as Da, ad as Pa, ae as ta, af as Ra, ag as La, ah as Ma, ai as oa, aj as ra, ak as ba, al as na, am as Fa, an as ia, ao as la, ap as ga, aq as Ba, ar as ca, as as Ya, at as Ua, au as da, av as ua, aw as Ha, ax as pa, ay as ya, az as Ka, aA as ka, aB as ma, aC as Va, aD as Xa, aE as ha, aF as va, aG as Wa, aH as fa, aI as xa, aJ as za, aK as wa, aL as Za, aM as ja, aN as Qa, aO as qa, aP as Ja, aQ as $a, aR as a_, aS as __, aT as E_, aU as T_, aV as s_, aW as I_, aX as S_, aY as N_, aZ as e_, a_ as A_, a$ as O_, b0 as C_, b1 as G_, b2 as D_, b3 as P_, b4 as t_, b5 as R_, b6 as L_, b7 as M_, b8 as o_, b9 as r_, ba as b_, bb as n_, bc as F_, bd as i_, be as l_, bf as g_, bg as B_, bh as c_, bi as Y_, bj as U_, bk as d_, bl as u_, bm as H_, bn as p_, bo as y_, bp as K_, bq as k_, br as m_, bs as V_, bt as X_, bu as h_, bv as v_, bw as W_, bx as f_, by as x_, bz as z_, bA as w_, bB as Z_, bC as j_, bD as Q_, bE as q_, bF as J_, bG as $_, bH as aE, bI as _E, bJ as EE, bK as TE, bL as sE, bM as IE, bN as SE, bO as NE, bP as eE, bQ as AE, bR as OE, bS as CE, bT as GE, bU as DE, bV as PE, bW as tE, bX as RE, bY as LE, bZ as ME, b_ as oE, b$ as rE, c0 as bE, c1 as nE, c2 as FE, c3 as iE, c4 as lE, c5 as gE, c6 as BE, c7 as cE, c8 as YE, c9 as UE, ca as dE, cb as uE, cc as HE, cd as pE, ce as yE, cf as KE, cg as kE, ch as mE, ci as VE, cj as XE, ck as hE, cl as vE, cm as WE, cn as fE, co as xE } from "./lib-3NPiNYNp.js";
2
2
  import { createPinia as wE, setActivePinia as ZE } from "pinia";
3
3
  export {
4
4
  E as ABOUT_SECTION_SETTINGS_CONFIG,
@@ -60964,10 +60964,9 @@ const Kn = /* @__PURE__ */ Z6(GB1), WB1 = (e, t, n) => {
60964
60964
  function c() {
60965
60965
  if (!d) return null;
60966
60966
  try {
60967
- const U = vD(d.brandPageData);
60968
- return JSON.stringify(U);
60967
+ return JSON.stringify(vD(d.brandPageData));
60969
60968
  } catch (U) {
60970
- return console.error("history-store: failed to serialize brandPageData", U), null;
60969
+ return console.error("history-store: failed to serialize snapshot", U), null;
60971
60970
  }
60972
60971
  }
60973
60972
  const u = /* @__PURE__ */ new Set(["P", "SPAN", "MARK"]), p = /* @__PURE__ */ new Set(["STRONG", "EM", "U", "S"]), g = /* @__PURE__ */ new Set([
@@ -62190,10 +62189,10 @@ const Kn = /* @__PURE__ */ Z6(GB1), WB1 = (e, t, n) => {
62190
62189
  R2(() => n.context.isDesignCom, async () => {
62191
62190
  const M = P6().toLowerCase(), _ = n.context.isDesignCom ? "Dcom" : "BrandCrowd";
62192
62191
  try {
62193
- const { default: V } = await yk(/* @__PURE__ */ Object.assign({ "./watermark/CreatedOnBrandCrowd-de-de.vue": () => import("./CreatedOnBrandCrowd-de-de-4mxqeHPP.js"), "./watermark/CreatedOnBrandCrowd-en-us.vue": () => import("./CreatedOnBrandCrowd-en-us-DQN_hGjC.js"), "./watermark/CreatedOnBrandCrowd-es-es.vue": () => import("./CreatedOnBrandCrowd-es-es-gijtJMPK.js"), "./watermark/CreatedOnBrandCrowd-fr-ca.vue": () => import("./CreatedOnBrandCrowd-fr-ca-BcOADD0V.js"), "./watermark/CreatedOnBrandCrowd-fr-fr.vue": () => import("./CreatedOnBrandCrowd-fr-fr-BcOADD0V.js"), "./watermark/CreatedOnBrandCrowd-pt-br.vue": () => import("./CreatedOnBrandCrowd-pt-br-B5eEyjAo.js"), "./watermark/CreatedOnBrandCrowd-pt-pt.vue": () => import("./CreatedOnBrandCrowd-pt-pt-B5eEyjAo.js"), "./watermark/CreatedOnDcom-de-de.vue": () => import("./CreatedOnDcom-de-de-DSGP6AAT.js"), "./watermark/CreatedOnDcom-en-us.vue": () => import("./CreatedOnDcom-en-us-BOuoJM_x.js"), "./watermark/CreatedOnDcom-es-es.vue": () => import("./CreatedOnDcom-es-es-kbiGFyBV.js"), "./watermark/CreatedOnDcom-fr-ca.vue": () => import("./CreatedOnDcom-fr-ca-BVFxrE6-.js"), "./watermark/CreatedOnDcom-fr-fr.vue": () => import("./CreatedOnDcom-fr-fr-92xJGi0w.js"), "./watermark/CreatedOnDcom-pt-br.vue": () => import("./CreatedOnDcom-pt-br-C40X9FAV.js"), "./watermark/CreatedOnDcom-pt-pt.vue": () => import("./CreatedOnDcom-pt-pt-CXxJUTUx.js") }), `./watermark/CreatedOn${_}-${M}.vue`, 3);
62192
+ const { default: V } = await yk(/* @__PURE__ */ Object.assign({ "./watermark/CreatedOnBrandCrowd-de-de.vue": () => import("./CreatedOnBrandCrowd-de-de-D0AQ4h1Y.js"), "./watermark/CreatedOnBrandCrowd-en-us.vue": () => import("./CreatedOnBrandCrowd-en-us-Bz9D9FcQ.js"), "./watermark/CreatedOnBrandCrowd-es-es.vue": () => import("./CreatedOnBrandCrowd-es-es-B6EKNEDx.js"), "./watermark/CreatedOnBrandCrowd-fr-ca.vue": () => import("./CreatedOnBrandCrowd-fr-ca-DvC5JIAW.js"), "./watermark/CreatedOnBrandCrowd-fr-fr.vue": () => import("./CreatedOnBrandCrowd-fr-fr-DvC5JIAW.js"), "./watermark/CreatedOnBrandCrowd-pt-br.vue": () => import("./CreatedOnBrandCrowd-pt-br-tckhI2rl.js"), "./watermark/CreatedOnBrandCrowd-pt-pt.vue": () => import("./CreatedOnBrandCrowd-pt-pt-tckhI2rl.js"), "./watermark/CreatedOnDcom-de-de.vue": () => import("./CreatedOnDcom-de-de-BJAmW8nU.js"), "./watermark/CreatedOnDcom-en-us.vue": () => import("./CreatedOnDcom-en-us-0IxL5rtr.js"), "./watermark/CreatedOnDcom-es-es.vue": () => import("./CreatedOnDcom-es-es-j1tEaAuh.js"), "./watermark/CreatedOnDcom-fr-ca.vue": () => import("./CreatedOnDcom-fr-ca-BHD4nfCD.js"), "./watermark/CreatedOnDcom-fr-fr.vue": () => import("./CreatedOnDcom-fr-fr-D4b447yE.js"), "./watermark/CreatedOnDcom-pt-br.vue": () => import("./CreatedOnDcom-pt-br-6WIaKLxK.js"), "./watermark/CreatedOnDcom-pt-pt.vue": () => import("./CreatedOnDcom-pt-pt-DSvzJLxn.js") }), `./watermark/CreatedOn${_}-${M}.vue`, 3);
62194
62193
  i.value = V;
62195
62194
  } catch {
62196
- const { default: H } = await yk(/* @__PURE__ */ Object.assign({ "./watermark/CreatedOnBrandCrowd-en-us.vue": () => import("./CreatedOnBrandCrowd-en-us-DQN_hGjC.js"), "./watermark/CreatedOnDcom-en-us.vue": () => import("./CreatedOnDcom-en-us-BOuoJM_x.js") }), `./watermark/CreatedOn${_}-en-us.vue`, 3);
62195
+ const { default: H } = await yk(/* @__PURE__ */ Object.assign({ "./watermark/CreatedOnBrandCrowd-en-us.vue": () => import("./CreatedOnBrandCrowd-en-us-Bz9D9FcQ.js"), "./watermark/CreatedOnDcom-en-us.vue": () => import("./CreatedOnDcom-en-us-0IxL5rtr.js") }), `./watermark/CreatedOn${_}-en-us.vue`, 3);
62197
62196
  i.value = H;
62198
62197
  }
62199
62198
  }, {
@@ -75717,7 +75716,8 @@ const _3 = ne("uiContentSettings", {
75717
75716
  textObjects: []
75718
75717
  },
75719
75718
  makerFonts: [],
75720
- isLogoDraftSaved: !1
75719
+ isLogoDraftSaved: !1,
75720
+ variationsByDraftToken: {}
75721
75721
  }),
75722
75722
  actions: {
75723
75723
  async setStateAsync(e) {
@@ -75854,7 +75854,16 @@ const _3 = ne("uiContentSettings", {
75854
75854
  a.logoImageBase64Url = this.getEditableLogoVariationByVariationId(l).base64;
75855
75855
  }
75856
75856
  });
75857
- });
75857
+ }), this.logoDraftToken && (this.variationsByDraftToken[this.logoDraftToken] = this.editableLogoVariations.map((s) => ({ ...s })));
75858
+ },
75859
+ /**
75860
+ * Restore the variations grid for `logoDraftToken` from the per-token
75861
+ * cache. Called by `_syncLogoSettingsFromSnapshot` during undo/redo.
75862
+ * Returns true on cache hit.
75863
+ */
75864
+ restoreVariationsForDraftToken(e) {
75865
+ const t = this.variationsByDraftToken[e];
75866
+ return t ? (this.editableLogoVariations = t.map((n) => ({ ...n })), !0) : !1;
75858
75867
  },
75859
75868
  async updateMetadataAsync(e, t = !1, n) {
75860
75869
  const i = await this.postEditableLogoRequestAsync({
@@ -75881,12 +75890,13 @@ const _3 = ne("uiContentSettings", {
75881
75890
  upsertDraftMetadata(e) {
75882
75891
  var i;
75883
75892
  const t = S4(), n = t.getLogoDraftAssetByToken(this.logoDraftToken);
75884
- n ? n.metadata = e : t.addLogoDraftAsset({
75893
+ n ? (n.metadata = e, t.logoTemplateAsset && (n.templateAsset = { ...t.logoTemplateAsset })) : t.addLogoDraftAsset({
75885
75894
  logoDraftAsset: {
75886
75895
  token: this.logoDraftToken,
75887
75896
  metadata: e,
75888
75897
  tick: Date.now(),
75889
- isByo: ((i = t.logoTemplateAsset) == null ? void 0 : i.isByo) || !1
75898
+ isByo: ((i = t.logoTemplateAsset) == null ? void 0 : i.isByo) || !1,
75899
+ templateAsset: t.logoTemplateAsset ? { ...t.logoTemplateAsset } : void 0
75890
75900
  }
75891
75901
  });
75892
75902
  },
@@ -76622,18 +76632,18 @@ const _3 = ne("uiContentSettings", {
76622
76632
  }), e.isModifiedAfterTemplateApplied !== void 0 && (this.isModifiedAfterTemplateApplied = e.isModifiedAfterTemplateApplied), e.brandPageType && this.setBrandPageType({ brandPageType: e.brandPageType }), this.faviconUrl = e.faviconUrl, this.ogImageUrl = e.ogImageUrl, this.measurementID = e.measurementID, this.adsenseID = e.adsenseID, this.ogTitle = e.ogTitle, this.ogDescription = e.ogDescription, this.cookieOptions = e.cookieOptions, this.saveContactSettings = e.saveContactSettings, this._syncLogoSettingsFromSnapshot(e), this._fallbackSidebarIfSelectedContentMissing(e);
76623
76633
  },
76624
76634
  _syncLogoSettingsFromSnapshot(e) {
76625
- var r, a, l, d, c;
76626
- const t = De(), n = K4(), i = S4(), o = e.brandPageType === d1.default ? (d = (l = (a = (r = e.pages) == null ? void 0 : r[0]) == null ? void 0 : a.contents) == null ? void 0 : l.find(
76627
- (u) => u.type === "logo"
76628
- )) == null ? void 0 : d.logoImage : (c = e.pageHeaderDesktop) == null ? void 0 : c.logoImage;
76635
+ var a, l, d, c, u;
76636
+ const t = De(), n = K4(), i = S4(), o = e.brandPageType === d1.default ? (c = (d = (l = (a = e.pages) == null ? void 0 : a[0]) == null ? void 0 : l.contents) == null ? void 0 : d.find(
76637
+ (p) => p.type === "logo"
76638
+ )) == null ? void 0 : c.logoImage : (u = e.pageHeaderDesktop) == null ? void 0 : u.logoImage;
76629
76639
  if (!o) return;
76630
76640
  t.setState({
76631
76641
  newState: { selectedLogoImage: o }
76632
76642
  });
76633
- const s = i.getLogoDraftAssetByToken(
76634
- o.logoDraftToken
76635
- );
76636
- s && n.setEnableEditMode(!s.isByo);
76643
+ const s = o.logoDraftToken;
76644
+ if (!s) return;
76645
+ const r = i.getLogoDraftAssetByToken(s);
76646
+ r && (n.setEnableEditMode(!r.isByo), r.templateAsset && i.setLogoTemplateAsset(r.templateAsset)), n.setLogoDraftToken(s), n.restoreVariationsForDraftToken(s);
76637
76647
  },
76638
76648
  _fallbackSidebarIfSelectedContentMissing(e) {
76639
76649
  var s;
@@ -93,6 +93,7 @@ declare const _default: import("vue").DefineComponent<{}, {
93
93
  logoTemplateMetadata: string;
94
94
  isLogoDraftSaved: boolean;
95
95
  isTextOnlyLogo: boolean;
96
+ variationsByDraftToken: Record<string, import("../store/editable-logo-store").EditableLogoVariation[]>;
96
97
  } & import("pinia").PiniaCustomStateProperties<import("../store/editable-logo-store").EditableLogoState>) => () => string | undefined;
97
98
  }, {
98
99
  setStateAsync(payload: {
@@ -110,6 +111,7 @@ declare const _default: import("vue").DefineComponent<{}, {
110
111
  getEditableLogoVariationByVariationId(id: number): any;
111
112
  getEditableLogoVariationByBase64(base64: string): any;
112
113
  updateEditableLogoImageUrlAsync(defaultPrimaryText?: string | undefined, overrideLogoVariation?: number | undefined, layout?: string | undefined): Promise<void>;
114
+ restoreVariationsForDraftToken(logoDraftToken: string): boolean;
113
115
  updateMetadataAsync(defaultPrimaryText?: string | undefined, resetLogoTemplateMetadata?: boolean, layout?: string | undefined): Promise<void>;
114
116
  updateEditableLogoImageByVariationAsync(editableLogoVariation: import("../store/editable-logo-store").EditableLogoVariation, defaultPrimaryText?: string | undefined, layout?: string | undefined): Promise<import("../../../clients/fabric-render-client").ModifyLogoDataResponse | null>;
115
117
  getDraftMetadata(logoDraftToken: string): string | undefined;
@@ -281,6 +281,7 @@ declare const _default: import("vue").DefineComponent<{}, {
281
281
  logoTemplateMetadata: string;
282
282
  isLogoDraftSaved: boolean;
283
283
  isTextOnlyLogo: boolean;
284
+ variationsByDraftToken: Record<string, import("../store").EditableLogoVariation[]>;
284
285
  } & import("pinia").PiniaCustomStateProperties<import("../store").EditableLogoState>) => () => string | undefined;
285
286
  }, {
286
287
  setStateAsync(payload: {
@@ -298,6 +299,7 @@ declare const _default: import("vue").DefineComponent<{}, {
298
299
  getEditableLogoVariationByVariationId(id: number): any;
299
300
  getEditableLogoVariationByBase64(base64: string): any;
300
301
  updateEditableLogoImageUrlAsync(defaultPrimaryText?: string | undefined, overrideLogoVariation?: number | undefined, layout?: string | undefined): Promise<void>;
302
+ restoreVariationsForDraftToken(logoDraftToken: string): boolean;
301
303
  updateMetadataAsync(defaultPrimaryText?: string | undefined, resetLogoTemplateMetadata?: boolean, layout?: string | undefined): Promise<void>;
302
304
  updateEditableLogoImageByVariationAsync(editableLogoVariation: import("../store").EditableLogoVariation, defaultPrimaryText?: string | undefined, layout?: string | undefined): Promise<import("../../../clients/fabric-render-client").ModifyLogoDataResponse | null>;
303
305
  getDraftMetadata(logoDraftToken: string): string | undefined;
@@ -74,8 +74,9 @@ export interface EditableLogoState {
74
74
  logoTemplateMetadata: string;
75
75
  isLogoDraftSaved: boolean;
76
76
  isTextOnlyLogo: boolean;
77
+ variationsByDraftToken: Record<string, EditableLogoVariation[]>;
77
78
  }
78
- export type SetStateAsyncPayload = Omit<EditableLogoState, 'enableEditMode' | 'editableLogoVariations'>;
79
+ export type SetStateAsyncPayload = Omit<EditableLogoState, 'enableEditMode' | 'editableLogoVariations' | 'variationsByDraftToken'>;
79
80
  export declare const useUiEditableLogoStore: import("pinia").StoreDefinition<"uiEditableLogo", EditableLogoState, {
80
81
  getLogoPrimaryText: (state: {
81
82
  enableEditMode: boolean;
@@ -167,6 +168,7 @@ export declare const useUiEditableLogoStore: import("pinia").StoreDefinition<"ui
167
168
  logoTemplateMetadata: string;
168
169
  isLogoDraftSaved: boolean;
169
170
  isTextOnlyLogo: boolean;
171
+ variationsByDraftToken: Record<string, EditableLogoVariation[]>;
170
172
  } & import("pinia").PiniaCustomStateProperties<EditableLogoState>) => () => string | undefined;
171
173
  }, {
172
174
  setStateAsync(payload: {
@@ -184,6 +186,12 @@ export declare const useUiEditableLogoStore: import("pinia").StoreDefinition<"ui
184
186
  getEditableLogoVariationByVariationId(id: number): any;
185
187
  getEditableLogoVariationByBase64(base64: string): any;
186
188
  updateEditableLogoImageUrlAsync(defaultPrimaryText?: string, overrideLogoVariation?: number | undefined, layout?: string): Promise<void>;
189
+ /**
190
+ * Restore the variations grid for `logoDraftToken` from the per-token
191
+ * cache. Called by `_syncLogoSettingsFromSnapshot` during undo/redo.
192
+ * Returns true on cache hit.
193
+ */
194
+ restoreVariationsForDraftToken(logoDraftToken: string): boolean;
187
195
  updateMetadataAsync(defaultPrimaryText?: string, resetLogoTemplateMetadata?: boolean, layout?: string): Promise<void>;
188
196
  updateEditableLogoImageByVariationAsync(editableLogoVariation: EditableLogoVariation, defaultPrimaryText?: string, layout?: string): Promise<ModifyLogoDataResponse | null>;
189
197
  getDraftMetadata(logoDraftToken: string): string | undefined;
@@ -74,6 +74,7 @@ export const useUiEditableLogoStore = defineStore('uiEditableLogo', {
74
74
  },
75
75
  makerFonts: [],
76
76
  isLogoDraftSaved: false,
77
+ variationsByDraftToken: {},
77
78
  }),
78
79
  actions: {
79
80
  async setStateAsync(payload) {
@@ -242,6 +243,28 @@ export const useUiEditableLogoStore = defineStore('uiEditableLogo', {
242
243
  }
243
244
  });
244
245
  });
246
+ // Stash the freshly rendered variation set under the active draft
247
+ // token so undo can restore it later without re-rendering. This is
248
+ // the only place in production that meaningfully populates
249
+ // `editableLogoVariations` (BYO upload + designed-logo setStateAsync
250
+ // both funnel here), so caching here keeps every distinct draft's
251
+ // grid available for the lifetime of the session.
252
+ if (this.logoDraftToken) {
253
+ this.variationsByDraftToken[this.logoDraftToken] =
254
+ this.editableLogoVariations.map((v) => ({ ...v }));
255
+ }
256
+ },
257
+ /**
258
+ * Restore the variations grid for `logoDraftToken` from the per-token
259
+ * cache. Called by `_syncLogoSettingsFromSnapshot` during undo/redo.
260
+ * Returns true on cache hit.
261
+ */
262
+ restoreVariationsForDraftToken(logoDraftToken) {
263
+ const cached = this.variationsByDraftToken[logoDraftToken];
264
+ if (!cached)
265
+ return false;
266
+ this.editableLogoVariations = cached.map((v) => ({ ...v }));
267
+ return true;
245
268
  },
246
269
  async updateMetadataAsync(defaultPrimaryText, resetLogoTemplateMetadata = false, layout) {
247
270
  const result = await this.postEditableLogoRequestAsync({
@@ -285,6 +308,13 @@ export const useUiEditableLogoStore = defineStore('uiEditableLogo', {
285
308
  const logoDraft = logoStore.getLogoDraftAssetByToken(this.logoDraftToken);
286
309
  if (logoDraft) {
287
310
  logoDraft.metadata = metadata;
311
+ // Refresh the template-asset stamp in case the active asset has
312
+ // changed since this draft was first registered (e.g. successive
313
+ // BYO uploads that share an existing draft token would otherwise
314
+ // keep pointing at an older template).
315
+ if (logoStore.logoTemplateAsset) {
316
+ logoDraft.templateAsset = { ...logoStore.logoTemplateAsset };
317
+ }
288
318
  }
289
319
  else {
290
320
  logoStore.addLogoDraftAsset({
@@ -293,6 +323,9 @@ export const useUiEditableLogoStore = defineStore('uiEditableLogo', {
293
323
  metadata,
294
324
  tick: Date.now(),
295
325
  isByo: logoStore.logoTemplateAsset?.isByo || false,
326
+ templateAsset: logoStore.logoTemplateAsset
327
+ ? { ...logoStore.logoTemplateAsset }
328
+ : undefined,
296
329
  },
297
330
  });
298
331
  }
@@ -4274,6 +4274,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
4274
4274
  logoTemplateMetadata: string;
4275
4275
  isLogoDraftSaved: boolean;
4276
4276
  isTextOnlyLogo: boolean;
4277
+ variationsByDraftToken: Record<string, import("@shared/logo-settings/store").EditableLogoVariation[]>;
4277
4278
  } & import("pinia").PiniaCustomStateProperties<import("@shared/logo-settings/store").EditableLogoState>) => () => string | undefined;
4278
4279
  }, {
4279
4280
  setStateAsync(payload: {
@@ -4291,6 +4292,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
4291
4292
  getEditableLogoVariationByVariationId(id: number): any;
4292
4293
  getEditableLogoVariationByBase64(base64: string): any;
4293
4294
  updateEditableLogoImageUrlAsync(defaultPrimaryText?: string | undefined, overrideLogoVariation?: number | undefined, layout?: string | undefined): Promise<void>;
4295
+ restoreVariationsForDraftToken(logoDraftToken: string): boolean;
4294
4296
  updateMetadataAsync(defaultPrimaryText?: string | undefined, resetLogoTemplateMetadata?: boolean, layout?: string | undefined): Promise<void>;
4295
4297
  updateEditableLogoImageByVariationAsync(editableLogoVariation: import("@shared/logo-settings/store").EditableLogoVariation, defaultPrimaryText?: string | undefined, layout?: string | undefined): Promise<import("../../../../clients/fabric-render-client").ModifyLogoDataResponse | null>;
4296
4298
  getDraftMetadata(logoDraftToken: string): string | undefined;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@designcrowd/library.brand-page",
3
3
  "description": "A collection of Maker/Designer applications",
4
- "version": "5.17.25-undo-12",
4
+ "version": "5.17.25-undo-14",
5
5
  "author": "Design.com Eng",
6
6
  "license": "UNLICENSED",
7
7
  "type": "module",
@@ -869,6 +869,9 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
869
869
  // restored header logo. The preview rehydrates via the page contents,
870
870
  // but `uiLogoSettings` holds its own copy that drives the sidebar
871
871
  // "current logo" state — same pattern as `initialiseStoresByBrandPageModelAsync`.
872
+ // Also restores the variations grid + template asset for the
873
+ // snapshot's draft token (both are sidecars to `brandPageData` —
874
+ // BYO upload mutates them out of band).
872
875
  this._syncLogoSettingsFromSnapshot(snapshot);
873
876
 
874
877
  // 9. If the sidebar is editing a content item that no longer exists in
@@ -897,17 +900,30 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
897
900
  newState: { selectedLogoImage: logoImage },
898
901
  });
899
902
 
900
- // Re-derive `enableEditMode` so the sidebar's design/upload tabs
901
- // reflect the restored logo. BYO logos can't be edited in the design
902
- // surface, so `enableEditMode` must flip false on undo back to a BYO
903
- // upload and true on redo back to a designed logo. Logo drafts are
904
- // append-only during a session, so a token in the snapshot always
905
- // resolves here.
906
- const draft = logoStore.getLogoDraftAssetByToken(
907
- logoImage.logoDraftToken,
908
- );
903
+ const draftToken: string | undefined = logoImage.logoDraftToken;
904
+
905
+ if (!draftToken) return;
906
+
907
+ // Re-derive `enableEditMode` and the active template asset from the
908
+ // logo-store's draft registry. Drafts are append-only for the session,
909
+ // and BYO upload stamps `templateAsset` onto the registered draft when
910
+ // it lands — so the registered draft is enough to fully restore the
911
+ // sidebar's design/upload chooser without storing anything inside
912
+ // each history entry. The variations grid is restored from the
913
+ // editable-logo store's per-token cache (populated by every
914
+ // `updateEditableLogoImageUrlAsync` render).
915
+ const draft = logoStore.getLogoDraftAssetByToken(draftToken);
916
+
917
+ if (draft) {
918
+ editableLogoStore.setEnableEditMode(!draft.isByo);
919
+
920
+ if (draft.templateAsset) {
921
+ logoStore.setLogoTemplateAsset(draft.templateAsset);
922
+ }
923
+ }
909
924
 
910
- if (draft) editableLogoStore.setEnableEditMode(!draft.isByo);
925
+ editableLogoStore.setLogoDraftToken(draftToken);
926
+ editableLogoStore.restoreVariationsForDraftToken(draftToken);
911
927
  },
912
928
 
913
929
  _fallbackSidebarIfSelectedContentMissing(snapshot: BrandPageModel): void {
@@ -82,7 +82,7 @@ describe('history-store (single stack + JSON-string snapshots)', () => {
82
82
  const entry = store.entries[0];
83
83
 
84
84
  expect(typeof entry.snapshot).toBe('string');
85
- // Round-trips to the same model via JSON.parse
85
+ // Round-trips to the same model via JSON.parse.
86
86
  expect(JSON.parse(entry.snapshot)).toMatchObject(
87
87
  mockMakerStore.brandPageData,
88
88
  );
@@ -743,7 +743,7 @@ describe('history-store (single stack + JSON-string snapshots)', () => {
743
743
  const store = useHistoryStore();
744
744
 
745
745
  await store.captureBaseline();
746
- const baselineSnapshot = JSON.parse(store.entries[0].snapshot);
746
+ const baselineBrandPageData = JSON.parse(store.entries[0].snapshot);
747
747
 
748
748
  captureMutated(store);
749
749
 
@@ -755,10 +755,10 @@ describe('history-store (single stack + JSON-string snapshots)', () => {
755
755
  expect(store.currentIndex).toBe(0);
756
756
  expect(store.entries.length).toBe(2); // stack is unchanged, pointer moved
757
757
  expect(mockMakerStore.applyHistorySnapshot).toHaveBeenCalledTimes(1);
758
- // Undo restores the baseline snapshot — the parsed object passed to
759
- // applyHistorySnapshot must round-trip to the captured baseline.
758
+ // Undo restores the baseline snapshot — the parsed BrandPageModel must
759
+ // round-trip back through applyHistorySnapshot.
760
760
  expect(mockMakerStore.applyHistorySnapshot).toHaveBeenCalledWith(
761
- expect.objectContaining(baselineSnapshot),
761
+ expect.objectContaining(baselineBrandPageData),
762
762
  );
763
763
  });
764
764
 
@@ -15,6 +15,12 @@ import { useEventTracker } from '../../composables/useEventTracker';
15
15
  * with the live store.
16
16
  * 2. `sizeBytes === snapshot.length` is automatic and accurate for the V2
17
17
  * memory-budget instrumentation.
18
+ *
19
+ * Sidecar state that doesn't live on `brandPageData` (the variations grid in
20
+ * the Logo sidebar, the active `logoTemplateAsset`, the active
21
+ * `logoDraftToken`) is restored on undo by `_syncLogoSettingsFromSnapshot`
22
+ * via per-draft-token caches on the logo / editable-logo stores — keyed off
23
+ * `logoImage.logoDraftToken` which IS in the snapshot.
18
24
  */
19
25
  export interface HistoryEntry {
20
26
  /** JSON.stringify(BrandPageModel) at the moment of capture. */
@@ -66,8 +72,10 @@ const CAPTURE_MAX_WAIT_MS = 10000;
66
72
  // FR-12: 40-entry cap. FR-13: 100 MB memory budget. FR-13c: per-entry
67
73
  // oversize threshold — entries above this are skipped + emit telemetry.
68
74
  // 25 MB accommodates a high-res BYO logo upload, which renders ~2.5 MB
69
- // of base64 PNG into each of four viewport sections (~10 MB) plus
70
- // per-page logo content blocks. The 100 MB total budget still evicts
75
+ // of base64 PNG into each of four viewport sections (~10 MB) plus per-page
76
+ // logo content blocks. The variations grid (~10 MB) does NOT live in the
77
+ // snapshot — it sits on the editable-logo store keyed by draft token, and
78
+ // is restored on undo from there. The 100 MB total budget still evicts
71
79
  // oldest non-baseline entries to keep memory bounded.
72
80
  const MAX_ENTRIES = 40;
73
81
  const MAX_MEMORY_BYTES = 100 * 1024 * 1024;
@@ -118,15 +126,13 @@ export const useHistoryStore = defineStore('history', () => {
118
126
  * Synchronous — safe to call inside a microtask without racing a follow-up
119
127
  * mutation.
120
128
  */
121
- function serializeCurrentBrandPageData(): string | null {
129
+ function serializeCurrentSnapshot(): string | null {
122
130
  if (!cachedMakerStore) return null;
123
131
 
124
132
  try {
125
- const raw = toRaw(cachedMakerStore.brandPageData);
126
-
127
- return JSON.stringify(raw);
133
+ return JSON.stringify(toRaw(cachedMakerStore.brandPageData));
128
134
  } catch (error) {
129
- console.error('history-store: failed to serialize brandPageData', error);
135
+ console.error('history-store: failed to serialize snapshot', error);
130
136
 
131
137
  return null;
132
138
  }
@@ -632,7 +638,7 @@ export const useHistoryStore = defineStore('history', () => {
632
638
 
633
639
  if (!baselineCaptured.value) return;
634
640
 
635
- const snapshot = serializeCurrentBrandPageData();
641
+ const snapshot = serializeCurrentSnapshot();
636
642
 
637
643
  if (!snapshot) return;
638
644
 
@@ -695,7 +701,7 @@ export const useHistoryStore = defineStore('history', () => {
695
701
 
696
702
  installWatcher();
697
703
 
698
- const snapshot = serializeCurrentBrandPageData();
704
+ const snapshot = serializeCurrentSnapshot();
699
705
 
700
706
  if (!snapshot) return;
701
707
 
@@ -731,7 +737,7 @@ export const useHistoryStore = defineStore('history', () => {
731
737
 
732
738
  if (!baselineCaptured.value) return 'skipped';
733
739
 
734
- const snapshot = serializeCurrentBrandPageData();
740
+ const snapshot = serializeCurrentSnapshot();
735
741
 
736
742
  if (!snapshot) return 'skipped';
737
743
 
@@ -14,6 +14,11 @@ export interface LogoDraftAsset {
14
14
  tick: number;
15
15
  isByo: boolean;
16
16
  logoEditUrl?: string;
17
+ // The `logoTemplateAsset` active when this draft was created. Stamped at
18
+ // upload/setState time so undo/redo can restore the right template token
19
+ // + isByo flag from a snapshot's `logoDraftToken` alone — without us
20
+ // bloating each history entry with a copy of the asset.
21
+ templateAsset?: LogoTemplateAsset;
17
22
  }
18
23
 
19
24
  export interface LogoStoreState {
@@ -116,11 +116,17 @@ export interface EditableLogoState {
116
116
  logoTemplateMetadata: string;
117
117
  isLogoDraftSaved: boolean;
118
118
  isTextOnlyLogo: boolean;
119
+ // Per-draft-token snapshot of `editableLogoVariations`. Repopulated each
120
+ // time `updateEditableLogoImageUrlAsync` finishes rendering for the active
121
+ // draft. Undo/redo reads from this map to restore the variations grid for
122
+ // the snapshot's `logoDraftToken` instead of re-rendering through fabric-
123
+ // render or stuffing 4 base64 PNGs into every history entry.
124
+ variationsByDraftToken: Record<string, EditableLogoVariation[]>;
119
125
  }
120
126
 
121
127
  export type SetStateAsyncPayload = Omit<
122
128
  EditableLogoState,
123
- 'enableEditMode' | 'editableLogoVariations'
129
+ 'enableEditMode' | 'editableLogoVariations' | 'variationsByDraftToken'
124
130
  >;
125
131
 
126
132
  export const useUiEditableLogoStore = defineStore('uiEditableLogo', {
@@ -192,6 +198,7 @@ export const useUiEditableLogoStore = defineStore('uiEditableLogo', {
192
198
  },
193
199
  makerFonts: [],
194
200
  isLogoDraftSaved: false,
201
+ variationsByDraftToken: {},
195
202
  }),
196
203
  actions: {
197
204
  async setStateAsync(payload: {
@@ -442,6 +449,32 @@ export const useUiEditableLogoStore = defineStore('uiEditableLogo', {
442
449
  }
443
450
  });
444
451
  });
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
+ },
464
+
465
+ /**
466
+ * Restore the variations grid for `logoDraftToken` from the per-token
467
+ * cache. Called by `_syncLogoSettingsFromSnapshot` during undo/redo.
468
+ * Returns true on cache hit.
469
+ */
470
+ restoreVariationsForDraftToken(logoDraftToken: string): boolean {
471
+ const cached = this.variationsByDraftToken[logoDraftToken];
472
+
473
+ if (!cached) return false;
474
+
475
+ this.editableLogoVariations = cached.map((v) => ({ ...v }));
476
+
477
+ return true;
445
478
  },
446
479
 
447
480
  async updateMetadataAsync(
@@ -506,6 +539,14 @@ export const useUiEditableLogoStore = defineStore('uiEditableLogo', {
506
539
 
507
540
  if (logoDraft) {
508
541
  logoDraft.metadata = metadata;
542
+
543
+ // Refresh the template-asset stamp in case the active asset has
544
+ // changed since this draft was first registered (e.g. successive
545
+ // BYO uploads that share an existing draft token would otherwise
546
+ // keep pointing at an older template).
547
+ if (logoStore.logoTemplateAsset) {
548
+ logoDraft.templateAsset = { ...logoStore.logoTemplateAsset };
549
+ }
509
550
  } else {
510
551
  logoStore.addLogoDraftAsset({
511
552
  logoDraftAsset: {
@@ -513,6 +554,9 @@ export const useUiEditableLogoStore = defineStore('uiEditableLogo', {
513
554
  metadata,
514
555
  tick: Date.now(),
515
556
  isByo: logoStore.logoTemplateAsset?.isByo || false,
557
+ templateAsset: logoStore.logoTemplateAsset
558
+ ? { ...logoStore.logoTemplateAsset }
559
+ : undefined,
516
560
  },
517
561
  });
518
562
  }